Compare commits
9
Commits
main
..
7a538e7316
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a538e7316 | ||
|
|
ffbef12812 | ||
|
|
9fe584d08e | ||
|
|
e66ecc4b59 | ||
|
|
b40c928051 | ||
|
|
ad203eb2ee | ||
|
|
91b0e371f7 | ||
|
|
783127296a | ||
|
|
111adb272e |
No files matched your search
@@ -14,6 +14,11 @@ venv/
|
||||
# NOTE: artifacts/partitions/ and artifacts/analysis/ are intentionally NOT ignored:
|
||||
# partition manifests are deterministic, content-hashed, and required for paired
|
||||
# comparisons; analysis outputs are small. They are intended to be version controlled.
|
||||
# EXCEPTION: the 18 beta0-round-0 prototype snapshots (and their effect/weight
|
||||
# CSVs) ARE tracked; the remaining ~76 snapshot JSONs (~28 MB, needed only to
|
||||
# regenerate already-committed displacement tables) stay local-only like
|
||||
# results/. They are cited by path in the audit documents; do not stage them.
|
||||
artifacts/analysis/*__prototype_snapshot.json
|
||||
artifacts/processed/
|
||||
artifacts/checkpoints/
|
||||
results/
|
||||
|
||||
@@ -170,7 +170,10 @@ Documented phases, in order. Session numbers are used only where the repository
|
||||
| Session 10 — 5G-NIDD a0.75 | second 5G-NIDD condition | `docs/research/5GNIDD_ALPHA075_BETA_VALIDATION.md`, `SESSION10_AUDIT.md` | audit PASS |
|
||||
| Session 11 — 5G-NIDD a0.25 | final condition; completes the grid | `docs/research/5GNIDD_ALPHA025_BETA_VALIDATION.md`, `SESSION11_AUDIT.md` | audit PASS |
|
||||
| Session 12 — synthesis | consolidate all six conditions | `docs/research/FINAL_EXPERIMENTAL_SYNTHESIS.md`, `CROSS_DATASET_BETA_ANALYSIS.md`, `docs/thesis/*`, `artifacts/analysis/final__*`, `artifacts/figures/final/*` | independent recomputation, zero mismatches |
|
||||
| Deep paired comparison | original vs proposed per condition | `docs/research/ORIGINAL_VS_PROPOSED_DEEP_COMPARISON.md`, `artifacts/analysis/deepcmp__*.csv`, `scripts/deep_comparison.py`, `scripts/make_comparison_figures.py` | manifest-hash pairing checks in code |
|
||||
| Post-hoc statistical audit | exploratory paired tests, selection stability | `docs/research/POSTHOC_STATISTICAL_AUDIT.md`, `artifacts/analysis/posthoc__*.csv`, `scripts/posthoc_statistical_audit.py` | manifest-hash pairing re-verified in code |
|
||||
| Proposal phase | write the thesis proposal and audit aids | `docs/proposal/*` | committed `e27c5a8` |
|
||||
| Defense preparation | robustness audit and examiner Q&A aids | `kisikisithesis/ROBUSTNESS_AUDIT_DAN_PERSIAPAN_PENGUJI.md`, `kisikisithesis/robustness_checks.py` | read-only checks over the actual implementation and persisted snapshots |
|
||||
| Handoff / README | keep repository state current | `docs/handoff/SESSION_HANDOFF.md`, `README.md` | this document |
|
||||
|
||||
## 7. Experiment Coverage and Reproducibility
|
||||
@@ -234,9 +237,16 @@ run. No scikit-learn `classification_report` is used; metrics are pure NumPy.
|
||||
- **Per-seed** values and **pooled** values are different quantities; the pooled score averages
|
||||
per-seed per-client-mean scores.
|
||||
|
||||
**Not computed by this repository:** micro-F1, ROC/AUC, statistical significance tests, and
|
||||
persisted per-class unseen-class recall (unseen-class evaluation is defined in code but only the
|
||||
unseen flags and union counts are saved).
|
||||
**Not computed by this repository:** micro-F1, ROC/AUC, and persisted per-class unseen-class
|
||||
recall (unseen-class evaluation is defined in code but only the unseen flags and union counts
|
||||
are saved).
|
||||
|
||||
**Exploratory statistical audit (no inferential claims).** `scripts/posthoc_statistical_audit.py`
|
||||
(read-only) computes paired per-seed deltas for the selected beta and exploratory exact tests
|
||||
(two-sided sign-flip permutation, exact Wilcoxon signed-rank) plus paired-t 95% CIs — all with
|
||||
explicit small-n limitations: three seeds give a minimum attainable sign-flip p of 0.25, so no
|
||||
statistical significance is claimed anywhere. Outputs: `artifacts/analysis/posthoc__*.csv`;
|
||||
full discussion in `docs/research/POSTHOC_STATISTICAL_AUDIT.md`.
|
||||
|
||||
## 9. Quantitative Experimental Results
|
||||
|
||||
@@ -759,10 +769,11 @@ scripts/ training runner, partition generation, and read-only ana
|
||||
configs/ dataset, experiment protocol, and model configuration (YAML)
|
||||
docs/proposal/ thesis proposal and internal audit aids
|
||||
docs/research/ frozen protocol, per-condition reports, cross-alpha/cross-dataset synthesis,
|
||||
session audits
|
||||
post-hoc statistical audit, session audits
|
||||
docs/baseline/ PROTEAN baseline investigation, implementation, and validation
|
||||
docs/thesis/ Chapter 4 blueprint and claims register
|
||||
docs/handoff/ session handoff (start here for a new session)
|
||||
kisikisithesis/ robustness audit and examiner-preparation aids (read-only checks)
|
||||
planningawal/ immutable research specification (do not modify)
|
||||
artifacts/partitions/ deterministic frozen Dirichlet partition manifests (18)
|
||||
artifacts/analysis/ committed machine-readable analysis outputs
|
||||
@@ -787,6 +798,12 @@ results/ local run outputs (git-ignored; 108 non-smoke run dirs +
|
||||
|
||||
# beta=0 vs original equivalence audit (read-only)
|
||||
.venv/bin/python scripts/verify_beta0_equivalence.py --dataset 5gnidd --alpha 0.25 --seeds 0 1 2
|
||||
|
||||
# post-hoc statistical audit (read-only; writes only posthoc__*.csv)
|
||||
.venv/bin/python scripts/posthoc_statistical_audit.py
|
||||
|
||||
# deterministic robustness checks over the actual implementation (prints only)
|
||||
.venv/bin/python kisikisithesis/robustness_checks.py
|
||||
```
|
||||
|
||||
A full training run (not needed; the grid is complete) is:
|
||||
@@ -842,6 +859,7 @@ Analysis outputs (`artifacts/analysis/`), by function:
|
||||
| Per-condition test | `*__multiseed__test_descriptive.csv` |
|
||||
| Cross-alpha | `{xiiotid,5gnidd}__cross_alpha__*.csv/.json` |
|
||||
| Cross-dataset | `cross_dataset__matched_alpha_summary.csv/.json`, `cross_dataset__beta_curve.csv` |
|
||||
| Post-hoc audit | `posthoc__paired_global_per_seed.csv`, `posthoc__paired_global_by_condition.csv`, `posthoc__paired_test_results.csv`, `posthoc__selection_stability.csv`, `posthoc__per_class_summary.csv`, `posthoc__per_client_summary.csv` |
|
||||
| beta=0 equivalence | `*__multiseed__beta0_equivalence.csv` |
|
||||
| Runtime | `*__multiseed__runtime.csv` |
|
||||
| Prototype snapshots & weights | `*__prototype_snapshot.json`, `*__prototype_weights.csv`, `*__prototype_effect*.csv` |
|
||||
@@ -859,6 +877,7 @@ Key documents:
|
||||
| `docs/research/FINAL_EXPERIMENTAL_SYNTHESIS.md` | authoritative six-condition synthesis |
|
||||
| `docs/research/ORIGINAL_VS_PROPOSED_DEEP_COMPARISON.md` | paired original-vs-proposed deep comparison |
|
||||
| `docs/research/CROSS_DATASET_BETA_ANALYSIS.md` | cross-dataset comparison |
|
||||
| `docs/research/POSTHOC_STATISTICAL_AUDIT.md` | exploratory paired statistical audit of the completed grid |
|
||||
| `docs/research/XIIOTID_CROSS_ALPHA_ANALYSIS.md` | X-IIoTID cross-alpha analysis |
|
||||
| `docs/research/5GNIDD_CROSS_ALPHA_ANALYSIS.md` | 5G-NIDD cross-alpha analysis |
|
||||
| `docs/thesis/CHAPTER4_RESULTS_OUTLINE.md` | Chapter 4 blueprint |
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
dataset,alpha,selected_beta,metric,original_seed0,original_seed1,original_seed2,proposed_seed0,proposed_seed1,proposed_seed2,delta_seed0,delta_seed1,delta_seed2,delta_mean,delta_std_sample,delta_median,delta_min,delta_max,baseline_std_sample,proposed_std_sample,n_pos,n_neg,n_zero,same_sign_all_seeds
|
||||
xiiotid,0.25,0.0,rare_class_macro_f1,0.6398103625587044,0.5825215614975117,0.6760389917828752,0.6413622282749385,0.5805553678969027,0.6744891962601014,0.0015518657162341132,-0.001966193600609012,-0.0015497955227737892,-0.0006547078023828959,0.0019222569702312445,-0.0015497955227737892,-0.001966193600609012,0.0015518657162341132,0.04715228886220545,0.04764177856302672,1,2,0,False
|
||||
xiiotid,0.25,0.0,rare_class_recall,0.8296012943628512,0.8266995877156649,0.8095946724338723,0.830700667573069,0.8256994230374527,0.807370314447251,0.0010993732102178022,-0.0010001646782121787,-0.0022243579866212393,-0.0007083831515385386,0.0016809668681122992,-0.0010001646782121787,-0.0022243579866212393,0.0010993732102178022,0.010810973971484781,0.012283281629867224,1,2,0,False
|
||||
xiiotid,0.25,0.0,macro_f1,0.6731025782780014,0.6669813754005415,0.7059686496708458,0.6745583013411162,0.6650385577782836,0.7044332575239617,0.001455723063114811,-0.0019428176222578974,-0.0015353921468841403,-0.0006741622353424089,0.0018557498263327506,-0.0015353921468841403,-0.0019428176222578974,0.001455723063114811,0.02096686007526524,0.020555132742947537,1,2,0,False
|
||||
xiiotid,0.25,0.0,weighted_f1,0.9054655196913645,0.9020747305215218,0.9154163421325315,0.9061557688476052,0.899863925003673,0.9146272396181951,0.0006902491562407187,-0.0022108055178488017,-0.0007891025143363928,-0.0007698862919814919,0.0014506227982888447,-0.0007891025143363928,-0.0022108055178488017,0.0006902491562407187,0.0069343939753111275,0.007408425095578143,1,2,0,False
|
||||
xiiotid,0.25,0.0,accuracy,0.8737218342944525,0.8673409854388906,0.8852306993140127,0.8745509147521049,0.8634903673133494,0.8840024319693425,0.000829080457652398,-0.0038506181255412164,-0.0012282673446701864,-0.0014166016708530016,0.0023455270348474206,-0.0012282673446701864,-0.0038506181255412164,0.000829080457652398,0.009066523301774463,0.010266545051804106,1,2,0,False
|
||||
xiiotid,0.5,0.75,rare_class_macro_f1,0.6096198579015474,0.655665402810942,0.662274505162012,0.6361887569975536,0.6719373483509694,0.6883814197743454,0.026568899096006238,0.01627194554002742,0.026106914612333387,0.022982586416122348,0.0058161742702334575,0.026106914612333387,0.01627194554002742,0.026568899096006238,0.028683282930463034,0.026684712591240056,3,0,0,True
|
||||
xiiotid,0.5,0.75,rare_class_recall,0.8714872155034664,0.8893650106408222,0.8700179539413673,0.8575434903523123,0.8518834947182458,0.878321192150252,-0.013943725151154163,-0.037481515922576425,0.008303238208884678,-0.014374000954948637,0.022895409598216065,-0.013943725151154163,-0.037481515922576425,0.008303238208884678,0.010770970951613777,0.013920609948849614,1,2,0,False
|
||||
xiiotid,0.5,0.75,macro_f1,0.7077011542142579,0.7091760460445067,0.7100168446133323,0.7262984173916737,0.7290145924987934,0.7381943369820925,0.018597263177415724,0.019838546454286732,0.028177492368760215,0.022204434000154222,0.005209919936951091,0.019838546454286732,0.018597263177415724,0.028177492368760215,0.0011722251041387443,0.006233755140268,3,0,0,True
|
||||
xiiotid,0.5,0.75,weighted_f1,0.9175853183547894,0.929132450103975,0.9274806689914715,0.9222775427473946,0.9447335103607959,0.9338838836432976,0.004692224392605193,0.015601060256820842,0.006403214651826028,0.008898833100417355,0.005867005927967981,0.006403214651826028,0.004692224392605193,0.015601060256820842,0.006244765764216191,0.011230108565482134,3,0,0,True
|
||||
xiiotid,0.5,0.75,accuracy,0.8904324115186911,0.9008849666218349,0.9070447273553561,0.8886698478790893,0.9254933028723031,0.9050119448999269,-0.0017625636396018107,0.02460833625046821,-0.0020327824554292606,0.006937663385145713,0.015303848018947405,-0.0017625636396018107,-0.0020327824554292606,0.02460833625046821,0.008398091032446977,0.018450460685614026,1,2,0,False
|
||||
xiiotid,0.75,0.5,rare_class_macro_f1,0.5215401253860467,0.6140607772418322,0.6760680764285393,0.5118888965076885,0.6241440493793726,0.6797040888050662,-0.00965122887835812,0.010083272137540455,0.003636012376526887,0.0013560185452364075,0.010062872924253166,0.003636012376526887,-0.00965122887835812,0.010083272137540455,0.07776445613264914,0.08548886486265879,2,1,0,False
|
||||
xiiotid,0.75,0.5,rare_class_recall,0.8164397897152784,0.8832376049795277,0.8698349315628103,0.8038871133887995,0.8767262170299326,0.8656806653880937,-0.01255267632647894,-0.00651138794959516,-0.004154266174716592,-0.007739443483596897,0.004331791034347159,-0.00651138794959516,-0.01255267632647894,-0.004154266174716592,0.03533794219558259,0.039255535276369505,0,3,0,True
|
||||
xiiotid,0.75,0.5,macro_f1,0.7424713724903063,0.7473954752926397,0.7656800124975965,0.741976732126316,0.7617524315559205,0.7691786586117774,-0.000494640363990273,0.014356956263280818,0.0034986461141808256,0.00578698733782379,0.007685691885683445,0.0034986461141808256,-0.000494640363990273,0.014356956263280818,0.012228464472937677,0.014060416901925107,2,1,0,False
|
||||
xiiotid,0.75,0.5,weighted_f1,0.9325633790408211,0.9359372345770101,0.9489075724365953,0.9355656459425888,0.9483435473557725,0.9517397334421744,0.0030022669017677472,0.012406312778762474,0.002832161005579148,0.00608024689536979,0.005479193934763414,0.0030022669017677472,0.002832161005579148,0.012406312778762474,0.008628878095570825,0.008528481213975155,3,0,0,True
|
||||
xiiotid,0.75,0.5,accuracy,0.9132536187826642,0.9138984591386161,0.9345763398861396,0.9143652007295908,0.9326111121346672,0.9373522240850943,0.0011115819469266208,0.01871265299605107,0.0027758841989546923,0.0075333730473107945,0.009717237293889463,0.0027758841989546923,0.0011115819469266208,0.01871265299605107,0.012128815595858657,0.012136684529934048,3,0,0,True
|
||||
5gnidd,0.25,0.0,rare_class_macro_f1,0.8649030079014913,0.8148479924290983,0.8470722146704726,0.8598927442995293,0.8138885616043564,0.8499254383428447,-0.005010263601961995,-0.0009594308247419248,0.0028532236723721738,-0.0010388235847772487,0.003932344775851092,-0.0009594308247419248,-0.005010263601961995,0.0028532236723721738,0.02537006851997817,0.024201888695409735,1,2,0,False
|
||||
5gnidd,0.25,0.0,rare_class_recall,0.9854440969271964,0.9723332887819381,0.9238897222901731,0.9852344223763528,0.9726587864975359,0.9257555179886866,-0.00020967455084353048,0.00032549771559775564,0.0018657956985135282,0.0006605396210892511,0.001077536077269848,0.00032549771559775564,-0.00020967455084353048,0.0018657956985135282,0.032423277290702865,0.03134699156678076,2,1,0,False
|
||||
5gnidd,0.25,0.0,macro_f1,0.8350430568226094,0.8083728869633723,0.8148003580492102,0.8296799384783186,0.8029871664481885,0.8172541498613525,-0.005363118344290818,-0.005385720515183823,0.0024537918121422253,-0.0027650156824441385,0.004519633996652314,-0.005363118344290818,-0.005385720515183823,0.0024537918121422253,0.013918675694370832,0.01335696520619808,1,2,0,False
|
||||
5gnidd,0.25,0.0,weighted_f1,0.7180410173151626,0.7163267008884987,0.6819385320735543,0.7174035576457394,0.7123024521167044,0.6836842063399526,-0.0006374596694231904,-0.004024248771794303,0.0017456742663983782,-0.0009720113916063718,0.0028994735052727187,-0.0006374596694231904,-0.004024248771794303,0.0017456742663983782,0.02036694411653514,0.018175165847202895,1,2,0,False
|
||||
5gnidd,0.25,0.0,accuracy,0.745280186859777,0.7412954350123573,0.7063291347454734,0.7448442903728559,0.737779477499928,0.7080521595381142,-0.0004358964869211057,-0.0035159575124292797,0.0017230247926407483,-0.0007429430689032124,0.0026329531140602156,-0.0004358964869211057,-0.0035159575124292797,0.0017230247926407483,0.02143091560670625,0.019524710435296355,1,2,0,False
|
||||
5gnidd,0.5,1.0,rare_class_macro_f1,0.8719637151922778,0.9211362509007983,0.8485250688106042,0.8809620350206805,0.8400749080738759,0.8949144498720359,0.008998319828402712,-0.08106134282692246,0.046389381061431756,-0.008557880645695995,0.06551402053172613,0.008998319828402712,-0.08106134282692246,0.046389381061431756,0.0370578200850738,0.028500884123071776,2,1,0,False
|
||||
5gnidd,0.5,1.0,rare_class_recall,0.9743136055202825,0.9685663953100676,0.9758591365273065,0.9743551890147765,0.9683408980660666,0.9586158518509788,4.1583494494012996e-05,-0.00022549724400100501,-0.01724328467632774,-0.0058090661419449114,0.009903224129001456,-0.00022549724400100501,-0.01724328467632774,4.1583494494012996e-05,0.0038428107281798614,0.0079422389145739,1,2,0,False
|
||||
5gnidd,0.5,1.0,macro_f1,0.8368808854359121,0.8654374620417004,0.8248673149789701,0.8504696755820977,0.8159411532871907,0.8493777051701392,0.013588790146185636,-0.04949630875450961,0.024510390191169074,-0.0037990428057183,0.039949974008521794,0.013588790146185636,-0.04949630875450961,0.024510390191169074,0.02083962881650294,0.019627422368850796,2,1,0,False
|
||||
5gnidd,0.5,1.0,weighted_f1,0.7087651452654392,0.7228023713469742,0.7246221247269671,0.7169500389469496,0.7201060072251736,0.7175295566399255,0.00818489368151043,-0.002696364121800632,-0.0070925680870416175,-0.0005346795091106064,0.007864786697422122,-0.002696364121800632,-0.0070925680870416175,0.00818489368151043,0.00867754781098361,0.0016799838366213199,1,2,0,False
|
||||
5gnidd,0.5,1.0,accuracy,0.7344156725348203,0.7473774246742085,0.7501326194500302,0.7428375216406157,0.7440259564021269,0.7429074295677633,0.008421849105795354,-0.003351468272081659,-0.007225189882266836,-0.0007182696828510471,0.008149095556025167,-0.003351468272081659,-0.007225189882266836,0.008421849105795354,0.008392660852506539,0.0006668791219600918,1,2,0,False
|
||||
5gnidd,0.75,0.5,rare_class_macro_f1,0.9055885946257963,0.8607580175603599,0.8733557623287002,0.9044472051910231,0.9057207431633723,0.8800449253698305,-0.0011413894347732656,0.0449627256030124,0.006689163041130319,0.01683683306978982,0.024670402532432648,0.006689163041130319,-0.0011413894347732656,0.0449627256030124,0.023120839413686988,0.014470318925337908,2,1,0,False
|
||||
5gnidd,0.75,0.5,rare_class_recall,0.9612851237375019,0.9590357221091453,0.9633214115686995,0.9586662658643216,0.9597228673347585,0.960715099133502,-0.0026188578731802803,0.0006871452256131949,-0.0026063124351975997,-0.0015126750275882284,0.0019051105497581826,-0.0026063124351975997,-0.0026188578731802803,0.0006871452256131949,0.002143727670860224,0.001024585149761231,1,2,0,False
|
||||
5gnidd,0.75,0.5,macro_f1,0.8571092007836155,0.8298666656506455,0.8372382392225877,0.8573089581866151,0.8599385529838828,0.842201195406295,0.00019975740299960076,0.03007188733323729,0.0049629561837073455,0.011744866973314746,0.016049354258377363,0.0049629561837073455,0.00019975740299960076,0.03007188733323729,0.014091078328488028,0.009572296127013734,3,0,0,True
|
||||
5gnidd,0.75,0.5,weighted_f1,0.7210591954237406,0.7299504931440421,0.7271326093968319,0.7238852910350473,0.7301094421086752,0.7284075566369677,0.002826095611306645,0.00015894896463308772,0.0012749472401357709,0.001419997272025168,0.0013394765554233625,0.0012749472401357709,0.00015894896463308772,0.002826095611306645,0.004543897028843019,0.0032168140791904,3,0,0,True
|
||||
5gnidd,0.75,0.5,accuracy,0.7470484461935134,0.7540721367563544,0.7517446140054364,0.7495075603367095,0.7543805540820061,0.7529330487669476,0.002459114143196106,0.00030841732565167757,0.0011884347615112034,0.0013186554101196624,0.0010812456997565073,0.0011884347615112034,0.00030841732565167757,0.002459114143196106,0.0035777922288362054,0.0025025090963709863,3,0,0,True
|
||||
|
@@ -0,0 +1,91 @@
|
||||
dataset,alpha,seed,selected_beta,metric,original,proposed,delta,manifest_content_hash,pairing_verified
|
||||
xiiotid,0.25,0,0.0,rare_class_macro_f1,0.6398103625587044,0.6413622282749385,0.0015518657162341132,839ba18e2d87245d198be8f5f89d4a24f13cdb6fc64c004d406c6d4f8246f3da,True
|
||||
xiiotid,0.25,0,0.0,rare_class_recall,0.8296012943628512,0.830700667573069,0.0010993732102178022,839ba18e2d87245d198be8f5f89d4a24f13cdb6fc64c004d406c6d4f8246f3da,True
|
||||
xiiotid,0.25,0,0.0,macro_f1,0.6731025782780014,0.6745583013411162,0.001455723063114811,839ba18e2d87245d198be8f5f89d4a24f13cdb6fc64c004d406c6d4f8246f3da,True
|
||||
xiiotid,0.25,0,0.0,weighted_f1,0.9054655196913645,0.9061557688476052,0.0006902491562407187,839ba18e2d87245d198be8f5f89d4a24f13cdb6fc64c004d406c6d4f8246f3da,True
|
||||
xiiotid,0.25,0,0.0,accuracy,0.8737218342944525,0.8745509147521049,0.000829080457652398,839ba18e2d87245d198be8f5f89d4a24f13cdb6fc64c004d406c6d4f8246f3da,True
|
||||
xiiotid,0.25,1,0.0,rare_class_macro_f1,0.5825215614975117,0.5805553678969027,-0.001966193600609012,84c20b4bd6cd20010fa35d139a0416cb06e79c82fbd8e1d57441cafdcdfbf15d,True
|
||||
xiiotid,0.25,1,0.0,rare_class_recall,0.8266995877156649,0.8256994230374527,-0.0010001646782121787,84c20b4bd6cd20010fa35d139a0416cb06e79c82fbd8e1d57441cafdcdfbf15d,True
|
||||
xiiotid,0.25,1,0.0,macro_f1,0.6669813754005415,0.6650385577782836,-0.0019428176222578974,84c20b4bd6cd20010fa35d139a0416cb06e79c82fbd8e1d57441cafdcdfbf15d,True
|
||||
xiiotid,0.25,1,0.0,weighted_f1,0.9020747305215218,0.899863925003673,-0.0022108055178488017,84c20b4bd6cd20010fa35d139a0416cb06e79c82fbd8e1d57441cafdcdfbf15d,True
|
||||
xiiotid,0.25,1,0.0,accuracy,0.8673409854388906,0.8634903673133494,-0.0038506181255412164,84c20b4bd6cd20010fa35d139a0416cb06e79c82fbd8e1d57441cafdcdfbf15d,True
|
||||
xiiotid,0.25,2,0.0,rare_class_macro_f1,0.6760389917828752,0.6744891962601014,-0.0015497955227737892,d6e68ee13cb11f98cfb4aea668f3e905d3ebc94884632352c0045fc5f86df28c,True
|
||||
xiiotid,0.25,2,0.0,rare_class_recall,0.8095946724338723,0.807370314447251,-0.0022243579866212393,d6e68ee13cb11f98cfb4aea668f3e905d3ebc94884632352c0045fc5f86df28c,True
|
||||
xiiotid,0.25,2,0.0,macro_f1,0.7059686496708458,0.7044332575239617,-0.0015353921468841403,d6e68ee13cb11f98cfb4aea668f3e905d3ebc94884632352c0045fc5f86df28c,True
|
||||
xiiotid,0.25,2,0.0,weighted_f1,0.9154163421325315,0.9146272396181951,-0.0007891025143363928,d6e68ee13cb11f98cfb4aea668f3e905d3ebc94884632352c0045fc5f86df28c,True
|
||||
xiiotid,0.25,2,0.0,accuracy,0.8852306993140127,0.8840024319693425,-0.0012282673446701864,d6e68ee13cb11f98cfb4aea668f3e905d3ebc94884632352c0045fc5f86df28c,True
|
||||
xiiotid,0.5,0,0.75,rare_class_macro_f1,0.6096198579015474,0.6361887569975536,0.026568899096006238,e81a6538ecefcda202aa7602310ff8d8c9529031ab9dcbec4ebbabc0e63b636c,True
|
||||
xiiotid,0.5,0,0.75,rare_class_recall,0.8714872155034664,0.8575434903523123,-0.013943725151154163,e81a6538ecefcda202aa7602310ff8d8c9529031ab9dcbec4ebbabc0e63b636c,True
|
||||
xiiotid,0.5,0,0.75,macro_f1,0.7077011542142579,0.7262984173916737,0.018597263177415724,e81a6538ecefcda202aa7602310ff8d8c9529031ab9dcbec4ebbabc0e63b636c,True
|
||||
xiiotid,0.5,0,0.75,weighted_f1,0.9175853183547894,0.9222775427473946,0.004692224392605193,e81a6538ecefcda202aa7602310ff8d8c9529031ab9dcbec4ebbabc0e63b636c,True
|
||||
xiiotid,0.5,0,0.75,accuracy,0.8904324115186911,0.8886698478790893,-0.0017625636396018107,e81a6538ecefcda202aa7602310ff8d8c9529031ab9dcbec4ebbabc0e63b636c,True
|
||||
xiiotid,0.5,1,0.75,rare_class_macro_f1,0.655665402810942,0.6719373483509694,0.01627194554002742,54ea1df16a2e7998cc21c3cee86318dc02a2fd8396894371ebaab7f87bad7e98,True
|
||||
xiiotid,0.5,1,0.75,rare_class_recall,0.8893650106408222,0.8518834947182458,-0.037481515922576425,54ea1df16a2e7998cc21c3cee86318dc02a2fd8396894371ebaab7f87bad7e98,True
|
||||
xiiotid,0.5,1,0.75,macro_f1,0.7091760460445067,0.7290145924987934,0.019838546454286732,54ea1df16a2e7998cc21c3cee86318dc02a2fd8396894371ebaab7f87bad7e98,True
|
||||
xiiotid,0.5,1,0.75,weighted_f1,0.929132450103975,0.9447335103607959,0.015601060256820842,54ea1df16a2e7998cc21c3cee86318dc02a2fd8396894371ebaab7f87bad7e98,True
|
||||
xiiotid,0.5,1,0.75,accuracy,0.9008849666218349,0.9254933028723031,0.02460833625046821,54ea1df16a2e7998cc21c3cee86318dc02a2fd8396894371ebaab7f87bad7e98,True
|
||||
xiiotid,0.5,2,0.75,rare_class_macro_f1,0.662274505162012,0.6883814197743454,0.026106914612333387,be881ac63bc0057eca7c82d762d082344e1f4fbd1dff56a475898c6de977712a,True
|
||||
xiiotid,0.5,2,0.75,rare_class_recall,0.8700179539413673,0.878321192150252,0.008303238208884678,be881ac63bc0057eca7c82d762d082344e1f4fbd1dff56a475898c6de977712a,True
|
||||
xiiotid,0.5,2,0.75,macro_f1,0.7100168446133323,0.7381943369820925,0.028177492368760215,be881ac63bc0057eca7c82d762d082344e1f4fbd1dff56a475898c6de977712a,True
|
||||
xiiotid,0.5,2,0.75,weighted_f1,0.9274806689914715,0.9338838836432976,0.006403214651826028,be881ac63bc0057eca7c82d762d082344e1f4fbd1dff56a475898c6de977712a,True
|
||||
xiiotid,0.5,2,0.75,accuracy,0.9070447273553561,0.9050119448999269,-0.0020327824554292606,be881ac63bc0057eca7c82d762d082344e1f4fbd1dff56a475898c6de977712a,True
|
||||
xiiotid,0.75,0,0.5,rare_class_macro_f1,0.5215401253860467,0.5118888965076885,-0.00965122887835812,759f7e504a7d442101238726334d121a746ea4a8ff366428c1c174e47f358723,True
|
||||
xiiotid,0.75,0,0.5,rare_class_recall,0.8164397897152784,0.8038871133887995,-0.01255267632647894,759f7e504a7d442101238726334d121a746ea4a8ff366428c1c174e47f358723,True
|
||||
xiiotid,0.75,0,0.5,macro_f1,0.7424713724903063,0.741976732126316,-0.000494640363990273,759f7e504a7d442101238726334d121a746ea4a8ff366428c1c174e47f358723,True
|
||||
xiiotid,0.75,0,0.5,weighted_f1,0.9325633790408211,0.9355656459425888,0.0030022669017677472,759f7e504a7d442101238726334d121a746ea4a8ff366428c1c174e47f358723,True
|
||||
xiiotid,0.75,0,0.5,accuracy,0.9132536187826642,0.9143652007295908,0.0011115819469266208,759f7e504a7d442101238726334d121a746ea4a8ff366428c1c174e47f358723,True
|
||||
xiiotid,0.75,1,0.5,rare_class_macro_f1,0.6140607772418322,0.6241440493793726,0.010083272137540455,4a50ba219de20af14f6ad73976111659fba2d5b25cd5eeb1a2f21b76de0d9303,True
|
||||
xiiotid,0.75,1,0.5,rare_class_recall,0.8832376049795277,0.8767262170299326,-0.00651138794959516,4a50ba219de20af14f6ad73976111659fba2d5b25cd5eeb1a2f21b76de0d9303,True
|
||||
xiiotid,0.75,1,0.5,macro_f1,0.7473954752926397,0.7617524315559205,0.014356956263280818,4a50ba219de20af14f6ad73976111659fba2d5b25cd5eeb1a2f21b76de0d9303,True
|
||||
xiiotid,0.75,1,0.5,weighted_f1,0.9359372345770101,0.9483435473557725,0.012406312778762474,4a50ba219de20af14f6ad73976111659fba2d5b25cd5eeb1a2f21b76de0d9303,True
|
||||
xiiotid,0.75,1,0.5,accuracy,0.9138984591386161,0.9326111121346672,0.01871265299605107,4a50ba219de20af14f6ad73976111659fba2d5b25cd5eeb1a2f21b76de0d9303,True
|
||||
xiiotid,0.75,2,0.5,rare_class_macro_f1,0.6760680764285393,0.6797040888050662,0.003636012376526887,922b7bb15169302be7dd4d4eb1644d077537872e1e91fe59b7525b7e3343cc1c,True
|
||||
xiiotid,0.75,2,0.5,rare_class_recall,0.8698349315628103,0.8656806653880937,-0.004154266174716592,922b7bb15169302be7dd4d4eb1644d077537872e1e91fe59b7525b7e3343cc1c,True
|
||||
xiiotid,0.75,2,0.5,macro_f1,0.7656800124975965,0.7691786586117774,0.0034986461141808256,922b7bb15169302be7dd4d4eb1644d077537872e1e91fe59b7525b7e3343cc1c,True
|
||||
xiiotid,0.75,2,0.5,weighted_f1,0.9489075724365953,0.9517397334421744,0.002832161005579148,922b7bb15169302be7dd4d4eb1644d077537872e1e91fe59b7525b7e3343cc1c,True
|
||||
xiiotid,0.75,2,0.5,accuracy,0.9345763398861396,0.9373522240850943,0.0027758841989546923,922b7bb15169302be7dd4d4eb1644d077537872e1e91fe59b7525b7e3343cc1c,True
|
||||
5gnidd,0.25,0,0.0,rare_class_macro_f1,0.8649030079014913,0.8598927442995293,-0.005010263601961995,ab6d8a8b63d478c4f6cfd88f96ccc7e16e1902f5e2c0ceac0f38ea26cfcda788,True
|
||||
5gnidd,0.25,0,0.0,rare_class_recall,0.9854440969271964,0.9852344223763528,-0.00020967455084353048,ab6d8a8b63d478c4f6cfd88f96ccc7e16e1902f5e2c0ceac0f38ea26cfcda788,True
|
||||
5gnidd,0.25,0,0.0,macro_f1,0.8350430568226094,0.8296799384783186,-0.005363118344290818,ab6d8a8b63d478c4f6cfd88f96ccc7e16e1902f5e2c0ceac0f38ea26cfcda788,True
|
||||
5gnidd,0.25,0,0.0,weighted_f1,0.7180410173151626,0.7174035576457394,-0.0006374596694231904,ab6d8a8b63d478c4f6cfd88f96ccc7e16e1902f5e2c0ceac0f38ea26cfcda788,True
|
||||
5gnidd,0.25,0,0.0,accuracy,0.745280186859777,0.7448442903728559,-0.0004358964869211057,ab6d8a8b63d478c4f6cfd88f96ccc7e16e1902f5e2c0ceac0f38ea26cfcda788,True
|
||||
5gnidd,0.25,1,0.0,rare_class_macro_f1,0.8148479924290983,0.8138885616043564,-0.0009594308247419248,74df102e4edb4509ba32b2625aa6a99f4bbd1dbbac0fc61d3bcccd50f21475ba,True
|
||||
5gnidd,0.25,1,0.0,rare_class_recall,0.9723332887819381,0.9726587864975359,0.00032549771559775564,74df102e4edb4509ba32b2625aa6a99f4bbd1dbbac0fc61d3bcccd50f21475ba,True
|
||||
5gnidd,0.25,1,0.0,macro_f1,0.8083728869633723,0.8029871664481885,-0.005385720515183823,74df102e4edb4509ba32b2625aa6a99f4bbd1dbbac0fc61d3bcccd50f21475ba,True
|
||||
5gnidd,0.25,1,0.0,weighted_f1,0.7163267008884987,0.7123024521167044,-0.004024248771794303,74df102e4edb4509ba32b2625aa6a99f4bbd1dbbac0fc61d3bcccd50f21475ba,True
|
||||
5gnidd,0.25,1,0.0,accuracy,0.7412954350123573,0.737779477499928,-0.0035159575124292797,74df102e4edb4509ba32b2625aa6a99f4bbd1dbbac0fc61d3bcccd50f21475ba,True
|
||||
5gnidd,0.25,2,0.0,rare_class_macro_f1,0.8470722146704726,0.8499254383428447,0.0028532236723721738,061c094d1913f942267bdb5654d3c0d8cfef3fa592be6cd5a1845a5eb5cdc8f2,True
|
||||
5gnidd,0.25,2,0.0,rare_class_recall,0.9238897222901731,0.9257555179886866,0.0018657956985135282,061c094d1913f942267bdb5654d3c0d8cfef3fa592be6cd5a1845a5eb5cdc8f2,True
|
||||
5gnidd,0.25,2,0.0,macro_f1,0.8148003580492102,0.8172541498613525,0.0024537918121422253,061c094d1913f942267bdb5654d3c0d8cfef3fa592be6cd5a1845a5eb5cdc8f2,True
|
||||
5gnidd,0.25,2,0.0,weighted_f1,0.6819385320735543,0.6836842063399526,0.0017456742663983782,061c094d1913f942267bdb5654d3c0d8cfef3fa592be6cd5a1845a5eb5cdc8f2,True
|
||||
5gnidd,0.25,2,0.0,accuracy,0.7063291347454734,0.7080521595381142,0.0017230247926407483,061c094d1913f942267bdb5654d3c0d8cfef3fa592be6cd5a1845a5eb5cdc8f2,True
|
||||
5gnidd,0.5,0,1.0,rare_class_macro_f1,0.8719637151922778,0.8809620350206805,0.008998319828402712,0732582cf4510089212717816d2151f5706c7b361123be32cc353bdf4b7f78e6,True
|
||||
5gnidd,0.5,0,1.0,rare_class_recall,0.9743136055202825,0.9743551890147765,4.1583494494012996e-05,0732582cf4510089212717816d2151f5706c7b361123be32cc353bdf4b7f78e6,True
|
||||
5gnidd,0.5,0,1.0,macro_f1,0.8368808854359121,0.8504696755820977,0.013588790146185636,0732582cf4510089212717816d2151f5706c7b361123be32cc353bdf4b7f78e6,True
|
||||
5gnidd,0.5,0,1.0,weighted_f1,0.7087651452654392,0.7169500389469496,0.00818489368151043,0732582cf4510089212717816d2151f5706c7b361123be32cc353bdf4b7f78e6,True
|
||||
5gnidd,0.5,0,1.0,accuracy,0.7344156725348203,0.7428375216406157,0.008421849105795354,0732582cf4510089212717816d2151f5706c7b361123be32cc353bdf4b7f78e6,True
|
||||
5gnidd,0.5,1,1.0,rare_class_macro_f1,0.9211362509007983,0.8400749080738759,-0.08106134282692246,f43906e111a8342c102237fe21090b64cadcc6e94c77db0deee1497e87e86801,True
|
||||
5gnidd,0.5,1,1.0,rare_class_recall,0.9685663953100676,0.9683408980660666,-0.00022549724400100501,f43906e111a8342c102237fe21090b64cadcc6e94c77db0deee1497e87e86801,True
|
||||
5gnidd,0.5,1,1.0,macro_f1,0.8654374620417004,0.8159411532871907,-0.04949630875450961,f43906e111a8342c102237fe21090b64cadcc6e94c77db0deee1497e87e86801,True
|
||||
5gnidd,0.5,1,1.0,weighted_f1,0.7228023713469742,0.7201060072251736,-0.002696364121800632,f43906e111a8342c102237fe21090b64cadcc6e94c77db0deee1497e87e86801,True
|
||||
5gnidd,0.5,1,1.0,accuracy,0.7473774246742085,0.7440259564021269,-0.003351468272081659,f43906e111a8342c102237fe21090b64cadcc6e94c77db0deee1497e87e86801,True
|
||||
5gnidd,0.5,2,1.0,rare_class_macro_f1,0.8485250688106042,0.8949144498720359,0.046389381061431756,fe8b4fc6f0486cf4fadf97ea0e096e8c7439fadb1f4e747336313b3bfd52d023,True
|
||||
5gnidd,0.5,2,1.0,rare_class_recall,0.9758591365273065,0.9586158518509788,-0.01724328467632774,fe8b4fc6f0486cf4fadf97ea0e096e8c7439fadb1f4e747336313b3bfd52d023,True
|
||||
5gnidd,0.5,2,1.0,macro_f1,0.8248673149789701,0.8493777051701392,0.024510390191169074,fe8b4fc6f0486cf4fadf97ea0e096e8c7439fadb1f4e747336313b3bfd52d023,True
|
||||
5gnidd,0.5,2,1.0,weighted_f1,0.7246221247269671,0.7175295566399255,-0.0070925680870416175,fe8b4fc6f0486cf4fadf97ea0e096e8c7439fadb1f4e747336313b3bfd52d023,True
|
||||
5gnidd,0.5,2,1.0,accuracy,0.7501326194500302,0.7429074295677633,-0.007225189882266836,fe8b4fc6f0486cf4fadf97ea0e096e8c7439fadb1f4e747336313b3bfd52d023,True
|
||||
5gnidd,0.75,0,0.5,rare_class_macro_f1,0.9055885946257963,0.9044472051910231,-0.0011413894347732656,96cd9b90b71895da4fcfb8c575c76d3a07ca14e824d8190ca6299eedeba6d6a5,True
|
||||
5gnidd,0.75,0,0.5,rare_class_recall,0.9612851237375019,0.9586662658643216,-0.0026188578731802803,96cd9b90b71895da4fcfb8c575c76d3a07ca14e824d8190ca6299eedeba6d6a5,True
|
||||
5gnidd,0.75,0,0.5,macro_f1,0.8571092007836155,0.8573089581866151,0.00019975740299960076,96cd9b90b71895da4fcfb8c575c76d3a07ca14e824d8190ca6299eedeba6d6a5,True
|
||||
5gnidd,0.75,0,0.5,weighted_f1,0.7210591954237406,0.7238852910350473,0.002826095611306645,96cd9b90b71895da4fcfb8c575c76d3a07ca14e824d8190ca6299eedeba6d6a5,True
|
||||
5gnidd,0.75,0,0.5,accuracy,0.7470484461935134,0.7495075603367095,0.002459114143196106,96cd9b90b71895da4fcfb8c575c76d3a07ca14e824d8190ca6299eedeba6d6a5,True
|
||||
5gnidd,0.75,1,0.5,rare_class_macro_f1,0.8607580175603599,0.9057207431633723,0.0449627256030124,007c23564a44919bba2520d09645e6a99c2a60dd347e8ff8d69a59aaa8ca6db3,True
|
||||
5gnidd,0.75,1,0.5,rare_class_recall,0.9590357221091453,0.9597228673347585,0.0006871452256131949,007c23564a44919bba2520d09645e6a99c2a60dd347e8ff8d69a59aaa8ca6db3,True
|
||||
5gnidd,0.75,1,0.5,macro_f1,0.8298666656506455,0.8599385529838828,0.03007188733323729,007c23564a44919bba2520d09645e6a99c2a60dd347e8ff8d69a59aaa8ca6db3,True
|
||||
5gnidd,0.75,1,0.5,weighted_f1,0.7299504931440421,0.7301094421086752,0.00015894896463308772,007c23564a44919bba2520d09645e6a99c2a60dd347e8ff8d69a59aaa8ca6db3,True
|
||||
5gnidd,0.75,1,0.5,accuracy,0.7540721367563544,0.7543805540820061,0.00030841732565167757,007c23564a44919bba2520d09645e6a99c2a60dd347e8ff8d69a59aaa8ca6db3,True
|
||||
5gnidd,0.75,2,0.5,rare_class_macro_f1,0.8733557623287002,0.8800449253698305,0.006689163041130319,3134bea2d47a7336c725e8d1a904b1e15c115336c0f018d685e1780cd952590d,True
|
||||
5gnidd,0.75,2,0.5,rare_class_recall,0.9633214115686995,0.960715099133502,-0.0026063124351975997,3134bea2d47a7336c725e8d1a904b1e15c115336c0f018d685e1780cd952590d,True
|
||||
5gnidd,0.75,2,0.5,macro_f1,0.8372382392225877,0.842201195406295,0.0049629561837073455,3134bea2d47a7336c725e8d1a904b1e15c115336c0f018d685e1780cd952590d,True
|
||||
5gnidd,0.75,2,0.5,weighted_f1,0.7271326093968319,0.7284075566369677,0.0012749472401357709,3134bea2d47a7336c725e8d1a904b1e15c115336c0f018d685e1780cd952590d,True
|
||||
5gnidd,0.75,2,0.5,accuracy,0.7517446140054364,0.7529330487669476,0.0011884347615112034,3134bea2d47a7336c725e8d1a904b1e15c115336c0f018d685e1780cd952590d,True
|
||||
|
@@ -0,0 +1,31 @@
|
||||
dataset,alpha,selected_beta,metric,n_pairs,deltas,signflip_exact_p_two_sided,wilcoxon_exact_p_two_sided,paired_t_ci95_low,paired_t_ci95_high,min_attainable_signflip_p,note
|
||||
xiiotid,0.25,0.0,rare_class_macro_f1,3,0.001552|-0.001966|-0.001550,0.75,1.0,-0.005429858832977498,0.004120443228211705,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
xiiotid,0.25,0.0,rare_class_recall,3,0.001099|-0.001000|-0.002224,0.75,1.0,-0.004884136340091787,0.00346737003701471,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
xiiotid,0.25,0.0,macro_f1,3,0.001456|-0.001943|-0.001535,0.5,1.0,-0.005284100361706733,0.003935775891021916,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
xiiotid,0.25,0.0,weighted_f1,3,0.000690|-0.002211|-0.000789,0.5,1.0,-0.004373433090107915,0.002833660506144932,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
xiiotid,0.25,0.0,accuracy,3,0.000829|-0.003851|-0.001228,0.5,1.0,-0.0072432138310324955,0.004410010489326492,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
xiiotid,0.5,0.75,rare_class_macro_f1,3,0.026569|0.016272|0.026107,0.25,0.5,0.008534408575840131,0.03743076425640456,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
xiiotid,0.5,0.75,rare_class_recall,3,-0.013944|-0.037482|0.008303,0.5,1.0,-0.07124935135394075,0.042501349444043476,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
xiiotid,0.5,0.75,macro_f1,3,0.018597|0.019839|0.028177,0.25,0.5,0.009262275411828459,0.035146592588479984,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
xiiotid,0.5,0.75,weighted_f1,3,0.004692|0.015601|0.006403,0.25,0.5,-0.00567561757777198,0.02347328377860669,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
xiiotid,0.5,0.75,accuracy,3,-0.001763|0.024608|-0.002033,1.0,1.0,-0.031079202606995104,0.04495452937728653,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
xiiotid,0.75,0.5,rare_class_macro_f1,3,-0.009651|0.010083|0.003636,0.75,1.0,-0.02364154357009798,0.026353580660570797,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
xiiotid,0.75,0.5,rare_class_recall,3,-0.012553|-0.006511|-0.004154,0.25,0.5,-0.01850020894956627,0.003021321982372477,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
xiiotid,0.75,0.5,macro_f1,3,-0.000495|0.014357|0.003499,0.5,1.0,-0.013305329712970347,0.024879304388617927,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
xiiotid,0.75,0.5,weighted_f1,3,0.003002|0.012406|0.002832,0.25,0.5,-0.007530825385598827,0.019691319176338408,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
xiiotid,0.75,0.5,accuracy,3,0.001112|0.018713|0.002776,0.25,0.5,-0.01660558256426208,0.03167232865888367,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.25,0.0,rare_class_macro_f1,3,-0.005010|-0.000959|0.002853,0.75,1.0,-0.010807309536371811,0.008729662366817314,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.25,0.0,rare_class_recall,3,-0.000210|0.000325|0.001866,0.5,1.0,-0.002016208383762044,0.0033372876259405463,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.25,0.0,macro_f1,3,-0.005363|-0.005386|0.002454,0.5,1.0,-0.013992408934881363,0.008462377569993086,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.25,0.0,weighted_f1,3,-0.000637|-0.004024|0.001746,0.75,1.0,-0.008174702869020644,0.0062306800858079004,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.25,0.0,accuracy,3,-0.000436|-0.003516|0.001723,0.75,1.0,-0.007283561191671378,0.005797675053864953,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.5,1.0,rare_class_macro_f1,3,0.008998|-0.081061|0.046389,1.0,1.0,-0.17130372966859422,0.15418796837720225,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.5,1.0,rare_class_recall,3,0.000042|-0.000225|-0.017243,0.5,1.0,-0.0304100386644281,0.018791906380538275,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.5,1.0,macro_f1,3,0.013589|-0.049496|0.024510,1.0,1.0,-0.10304027980644635,0.09544219419500975,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.5,1.0,weighted_f1,3,0.008185|-0.002696|-0.007093,1.0,1.0,-0.020071892735646125,0.01900253371742491,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.5,1.0,accuracy,3,0.008422|-0.003351|-0.007225,1.0,1.0,-0.02096174526670406,0.019525205901001964,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.75,0.5,rare_class_macro_f1,3,-0.001141|0.044963|0.006689,0.5,1.0,-0.04444784421441203,0.07812151035399167,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.75,0.5,rare_class_recall,3,-0.002619|0.000687|-0.002606,0.5,1.0,-0.006245231988471588,0.0032198819332951312,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.75,0.5,macro_f1,3,0.000200|0.030072|0.004963,0.25,0.5,-0.028123939182216617,0.05161367312884611,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.75,0.5,weighted_f1,3,0.002826|0.000159|0.001275,0.25,0.5,-0.0019074469527278436,0.004747441496778179,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
5gnidd,0.75,0.5,accuracy,3,0.002459|0.000308|0.001188,0.25,0.5,-0.0013673078078454953,0.00400461862808482,0.25,"exploratory; 3 seeds; no inferential power; beta=0 conditions are numerical, not a treatment contrast"
|
||||
|
@@ -0,0 +1,19 @@
|
||||
dataset,class_name,n_obs,mean_delta_f1,median_delta_f1,min_delta_f1,max_delta_f1,n_positive,n_negative
|
||||
xiiotid,Tampering,9,0.05199619640670891,0.004580967510456113,-0.005430499483001561,0.214955968364532,6,3
|
||||
xiiotid,Reconnaissance,9,0.02952063666312104,0.008242346598957062,-0.0003622961256807278,0.10238198044760449,8,1
|
||||
5gnidd,ICMPFlood,9,0.026821108337293526,0.010408977770148542,-0.46986271362984083,0.3772516575720237,5,4
|
||||
5gnidd,TCPConnectScan,9,0.014211458390848499,0.000706524723936286,-0.019433003409767724,0.05772198907204773,6,3
|
||||
xiiotid,Lateral_movement,9,0.010881583240329038,0.0017846016589943003,-0.014168138453098611,0.07607557487760874,6,3
|
||||
xiiotid,Weaponization,9,0.009113660779203083,0.007233534576793765,-0.004643526037137802,0.03336802894144031,8,1
|
||||
xiiotid,Exploitation,9,0.006734945561392644,6.591764883166762e-05,-0.008223665637908967,0.036914135633034896,6,3
|
||||
5gnidd,Benign,9,0.0009395838996870687,0.00028927780247300916,-0.0012807529813573248,0.004784809629670872,5,4
|
||||
5gnidd,SYNScan,9,0.0007028996039083962,0.00012358980722271262,-0.0027240713350633605,0.0033494638084979877,6,2
|
||||
xiiotid,RDOS,9,0.00011273464532779442,0.0,-0.00020998786240000733,0.0008246202062063279,4,4
|
||||
5gnidd,UDPFlood,9,-5.0275925956781244e-05,-5.101815123376152e-05,-0.0004926348932754454,0.0004015231846284939,3,6
|
||||
5gnidd,UDPScan,9,-0.00029387524907019554,-0.0009226463398589457,-0.0038642666069870213,0.004913668121620529,3,6
|
||||
5gnidd,HTTPFlood,9,-0.0008211332125179031,0.0007952922021617903,-0.0344690095854302,0.03529511546161013,6,3
|
||||
xiiotid,Normal,9,-0.002240793040637389,-0.00027963176745748886,-0.0315329514150966,0.012717262317857747,4,5
|
||||
xiiotid,Exfiltration,9,-0.006129465975398516,0.0,-0.03964725823094428,0.004487347741842007,3,3
|
||||
5gnidd,SlowrateDoS,9,-0.006597630438252566,0.0017380510468695265,-0.047165133257141556,0.028229267253973345,5,4
|
||||
xiiotid,C&C,9,-0.018037720972140073,-0.005217928136442729,-0.16416853359506542,0.0321417804096471,4,5
|
||||
5gnidd,SYNFlood,9,-0.019369709950482903,-0.006397152956185925,-0.06835732738470357,0.00727579075336604,2,7
|
||||
|
@@ -0,0 +1,7 @@
|
||||
dataset,alpha,selected_beta,n_client_seed_obs,n_improved_gt_0.02,n_degraded_lt_-0.02,n_unchanged,mean_delta,median_delta,min_delta,max_delta,std_sample_within_condition
|
||||
5gnidd,0.25,0.0,30,1,0,29,0.002111576617816057,0.0,-0.019933554817275767,0.07142857142857151,0.01470740176243374
|
||||
5gnidd,0.5,1.0,30,15,6,9,0.03903400685752252,0.02024848480689545,-0.17567567567567566,0.4040650406504065,0.11851570462408138
|
||||
5gnidd,0.75,0.5,30,8,1,21,0.02071412212202052,0.004477101314292853,-0.03633656881678371,0.16839803756061722,0.043102741088679355
|
||||
xiiotid,0.25,0.0,30,1,1,28,-0.0015178066042212891,0.0,-0.026277262664796908,0.02494573827906854,0.00807984351701968
|
||||
xiiotid,0.5,0.75,30,12,1,17,0.03024920134564162,0.012286627106224551,-0.2565947651121153,0.3235930735930736,0.08670494898387493
|
||||
xiiotid,0.75,0.5,30,8,2,20,0.01167502563325023,0.010269879504053326,-0.0697526762643042,0.06759906759906764,0.026808060695173577
|
||||
|
@@ -0,0 +1,7 @@
|
||||
dataset,alpha,pooled_selected_beta,per_seed_beta_s0,per_seed_beta_s1,per_seed_beta_s2,n_seeds_agree_pooled,pooled_score_selected,second_best_beta,second_best_score,margin_best_minus_second,candidate_score_range,test_used_for_selection
|
||||
xiiotid,0.25,0.0,0.75,0.5,0.0,1,0.5917038146634539,0.25,0.5886906256417319,0.0030131890217219848,0.059605114021112016,False
|
||||
xiiotid,0.5,0.75,0.5,1.0,0.75,1,0.5793667895728949,1.0,0.5734790834215032,0.0058877061513916695,0.03500610197920917,False
|
||||
xiiotid,0.75,0.5,0.5,0.5,0.0,2,0.47674948263663786,0.25,0.47436809609801456,0.002381386538623298,0.008144253663347922,False
|
||||
5gnidd,0.25,0.0,0.25,0.0,0.0,2,0.7614534210908004,0.25,0.7492858468825279,0.012167574208272525,0.039218114350402566,False
|
||||
5gnidd,0.5,1.0,1.0,0.0,1.0,2,0.6923695590578484,0.75,0.6883680316141424,0.004001527443705966,0.04729182197574977,False
|
||||
5gnidd,0.75,0.5,0.5,1.0,1.0,1,0.8090814343293602,1.0,0.8043064619946296,0.004774972334730565,0.03098780223355102,False
|
||||
|
+46
@@ -0,0 +1,46 @@
|
||||
class_id,class_name,beta,n_contributors,support_min,support_max,support_mean,prototype_norm,reference_norm_beta0,displacement_from_beta0,relative_displacement
|
||||
0,C&C,0.0,8,2,687,250.5,4.995807261779628,4.995807261779628,0.0,0.0
|
||||
0,C&C,0.25,8,2,687,250.5,4.857134771566648,4.995807261779628,0.7971996511065712,0.1595737404053873
|
||||
0,C&C,0.5,8,2,687,250.5,4.906583708196013,4.995807261779628,1.2665743125302988,0.2535274573581356
|
||||
0,C&C,0.75,8,2,687,250.5,5.010855437469484,4.995807261779628,1.56068016232047,0.3123979930651924
|
||||
0,C&C,1.0,8,2,687,250.5,5.121849269773383,4.995807261779628,1.7701252868773527,0.35432217339921773
|
||||
1,Exfiltration,0.0,10,8,6273,1549.4,7.157109420154553,7.157109420154553,0.0,0.0
|
||||
1,Exfiltration,0.25,10,8,6273,1549.4,7.739024271072487,7.157109420154553,1.112938631376158,0.1555011340531
|
||||
1,Exfiltration,0.5,10,8,6273,1549.4,8.136996752575591,7.157109420154553,1.792423075103891,0.2504395238189868
|
||||
1,Exfiltration,0.75,10,8,6273,1549.4,8.4002894954015,7.157109420154553,2.2364541806817226,0.312480087894678
|
||||
1,Exfiltration,1.0,10,8,6273,1549.4,8.580132867813264,7.157109420154553,2.5469976586314798,0.35586959889967407
|
||||
2,Exploitation,0.0,9,1,491,88.11111111111111,5.992134154687249,5.992134154687249,0.0,0.0
|
||||
2,Exploitation,0.25,9,1,491,88.11111111111111,5.852057025355164,5.992134154687249,0.6403508338020284,0.10686523653698982
|
||||
2,Exploitation,0.5,9,1,491,88.11111111111111,5.649833686058244,5.992134154687249,1.3058952653326283,0.2179349179475752
|
||||
2,Exploitation,0.75,9,1,491,88.11111111111111,5.462810593200537,5.992134154687249,2.0362822833565866,0.3398258835316192
|
||||
2,Exploitation,1.0,9,1,491,88.11111111111111,5.361136450101408,5.992134154687249,2.7586985908860333,0.46038665351443886
|
||||
3,Lateral_movement,0.0,10,49,8361,2211.7,5.836739012783497,5.836739012783497,0.0,0.0
|
||||
3,Lateral_movement,0.25,10,49,8361,2211.7,6.244285935865453,5.836739012783497,0.7731353833893619,0.13246015997906674
|
||||
3,Lateral_movement,0.5,10,49,8361,2211.7,6.616077783217527,5.836739012783497,1.3883187562912933,0.2378586318919911
|
||||
3,Lateral_movement,0.75,10,49,8361,2211.7,6.909367469065839,5.836739012783497,1.8469497276568052,0.3164352087032942
|
||||
3,Lateral_movement,1.0,10,49,8361,2211.7,7.129359871034012,5.836739012783497,2.18587302323185,0.37450244364951035
|
||||
4,Normal,0.0,10,260,89253,29277.7,5.744022110217372,5.744022110217372,0.0,0.0
|
||||
4,Normal,0.25,10,260,89253,29277.7,6.310406949046281,5.744022110217372,0.7219321390806914,0.1256840808109931
|
||||
4,Normal,0.5,10,260,89253,29277.7,6.65485903802621,5.744022110217372,1.1590902280700377,0.20179069749892972
|
||||
4,Normal,0.75,10,260,89253,29277.7,6.856645071712252,5.744022110217372,1.4245372318857714,0.24800343810512637
|
||||
4,Normal,1.0,10,260,89253,29277.7,6.981584206588257,5.744022110217372,1.5984450234076382,0.2782797476639845
|
||||
5,RDOS,0.0,10,6,47276,9888.3,7.606714687573022,7.606714687573022,0.0,0.0
|
||||
5,RDOS,0.25,10,6,47276,9888.3,8.606801712435749,7.606714687573022,1.6366469943162223,0.21515819398221792
|
||||
5,RDOS,0.5,10,6,47276,9888.3,9.183021988100103,7.606714687573022,2.444982027217194,0.3214241795096542
|
||||
5,RDOS,0.75,10,6,47276,9888.3,9.572100709915908,7.606714687573022,2.932638911884029,0.38553291826168246
|
||||
5,RDOS,1.0,10,6,47276,9888.3,9.877736968852913,7.606714687573022,3.2852506457034076,0.43188824356334454
|
||||
6,Reconnaissance,0.0,10,1842,23967,8916.1,6.600587294730691,6.600587294730691,0.0,0.0
|
||||
6,Reconnaissance,0.25,10,1842,23967,8916.1,6.619642701782661,6.600587294730691,0.19750804124277122,0.02992279814259008
|
||||
6,Reconnaissance,0.5,10,1842,23967,8916.1,6.6531594178920175,6.600587294730691,0.37937859322083467,0.057476490542545514
|
||||
6,Reconnaissance,0.75,10,1842,23967,8916.1,6.698692451193534,6.600587294730691,0.5470003591054624,0.08287146804984122
|
||||
6,Reconnaissance,1.0,10,1842,23967,8916.1,6.75347500969919,6.600587294730691,0.7025557661555466,0.10643837203947037
|
||||
7,Tampering,0.0,9,8,1228,398.44444444444446,5.065268302764301,5.065268302764301,0.0,0.0
|
||||
7,Tampering,0.25,9,8,1228,398.44444444444446,5.155842974383021,5.065268302764301,0.5957873490790528,0.11762207122452131
|
||||
7,Tampering,0.5,9,8,1228,398.44444444444446,5.314632895746181,5.065268302764301,1.0369597200237384,0.20471960378837814
|
||||
7,Tampering,0.75,9,8,1228,398.44444444444446,5.475188209465522,5.065268302764301,1.3704230949002763,0.2705529130909781
|
||||
7,Tampering,1.0,9,8,1228,398.44444444444446,5.614041117925036,5.065268302764301,1.6272957425211183,0.32126545826467745
|
||||
8,Weaponization,0.0,10,917,11526,4509.4,6.991110809530167,6.991110809530167,0.0,0.0
|
||||
8,Weaponization,0.25,10,917,11526,4509.4,7.0769252730146075,6.991110809530167,0.36048411330770536,0.05156320978581821
|
||||
8,Weaponization,0.5,10,917,11526,4509.4,7.163738177542325,6.991110809530167,0.695561899244867,0.0994923293586891
|
||||
8,Weaponization,0.75,10,917,11526,4509.4,7.238525120169953,6.991110809530167,0.9758406496021348,0.13958306143165186
|
||||
8,Weaponization,1.0,10,917,11526,4509.4,7.292875462963678,6.991110809530167,1.189062205569606,0.17008201385517965
|
||||
|
+431
@@ -0,0 +1,431 @@
|
||||
class_id,class_name,beta,client_id,N_ij,weight
|
||||
0,C&C,0.0,0,2.0,0.125
|
||||
0,C&C,0.0,1,3.0,0.125
|
||||
0,C&C,0.0,3,687.0,0.125
|
||||
0,C&C,0.0,4,284.0,0.125
|
||||
0,C&C,0.0,5,599.0,0.125
|
||||
0,C&C,0.0,7,82.0,0.125
|
||||
0,C&C,0.0,8,236.0,0.125
|
||||
0,C&C,0.0,9,111.0,0.125
|
||||
0,C&C,0.25,0,2.0,0.044287795667630386
|
||||
0,C&C,0.25,1,3.0,0.049012502728748776
|
||||
0,C&C,0.25,3,687.0,0.19066270493474782
|
||||
0,C&C,0.25,4,284.0,0.15288192794120894
|
||||
0,C&C,0.25,5,599.0,0.1842397227452447
|
||||
0,C&C,0.25,7,82.0,0.11206758905036181
|
||||
0,C&C,0.25,8,236.0,0.145966961117219
|
||||
0,C&C,0.25,9,111.0,0.12088079581483864
|
||||
0,C&C,0.5,0,2.0,0.013387476143622101
|
||||
0,C&C,0.5,1,3.0,0.016396242747778414
|
||||
0,C&C,0.5,3,687.0,0.24812017604357262
|
||||
0,C&C,0.5,4,284.0,0.15953018988404427
|
||||
0,C&C,0.5,5,599.0,0.23168457650449506
|
||||
0,C&C,0.5,7,82.0,0.08572167297328072
|
||||
0,C&C,0.5,8,236.0,0.14542521467934644
|
||||
0,C&C,0.5,9,111.0,0.09973445102386046
|
||||
0,C&C,0.75,0,2.0,0.003736734114884092
|
||||
0,C&C,0.75,1,3.0,0.005064780649749788
|
||||
0,C&C,0.75,3,687.0,0.2981516746539658
|
||||
0,C&C,0.75,4,284.0,0.15371224135216596
|
||||
0,C&C,0.75,5,599.0,0.2690232512634536
|
||||
0,C&C,0.75,7,82.0,0.06054525177359796
|
||||
0,C&C,0.75,8,236.0,0.1337838538937557
|
||||
0,C&C,0.75,9,111.0,0.07598221229842717
|
||||
0,C&C,1.0,0,2.0,0.000998003992015968
|
||||
0,C&C,1.0,1,3.0,0.0014970059880239522
|
||||
0,C&C,1.0,3,687.0,0.34281437125748504
|
||||
0,C&C,1.0,4,284.0,0.14171656686626746
|
||||
0,C&C,1.0,5,599.0,0.29890219560878245
|
||||
0,C&C,1.0,7,82.0,0.04091816367265469
|
||||
0,C&C,1.0,8,236.0,0.11776447105788423
|
||||
0,C&C,1.0,9,111.0,0.05538922155688623
|
||||
1,Exfiltration,0.0,0,627.0,0.1
|
||||
1,Exfiltration,0.0,1,199.0,0.1
|
||||
1,Exfiltration,0.0,2,1006.0,0.1
|
||||
1,Exfiltration,0.0,3,916.0,0.1
|
||||
1,Exfiltration,0.0,4,6273.0,0.1
|
||||
1,Exfiltration,0.0,5,2759.0,0.1
|
||||
1,Exfiltration,0.0,6,2518.0,0.1
|
||||
1,Exfiltration,0.0,7,8.0,0.1
|
||||
1,Exfiltration,0.0,8,1113.0,0.1
|
||||
1,Exfiltration,0.0,9,75.0,0.1
|
||||
1,Exfiltration,0.25,0,627.0,0.0934897597942656
|
||||
1,Exfiltration,0.25,1,199.0,0.07017144629849609
|
||||
1,Exfiltration,0.25,2,1006.0,0.1052196018044885
|
||||
1,Exfiltration,0.25,3,916.0,0.1027829378876304
|
||||
1,Exfiltration,0.25,4,6273.0,0.16627079779754889
|
||||
1,Exfiltration,0.25,5,2759.0,0.13540511920488763
|
||||
1,Exfiltration,0.25,6,2518.0,0.1323460823920462
|
||||
1,Exfiltration,0.25,7,8.0,0.03142097487762249
|
||||
1,Exfiltration,0.25,8,1113.0,0.10791230019790968
|
||||
1,Exfiltration,0.25,9,75.0,0.054980979745104526
|
||||
1,Exfiltration,0.5,0,627.0,0.07636740343228143
|
||||
1,Exfiltration,0.5,1,199.0,0.04302301007227493
|
||||
1,Exfiltration,0.5,2,1006.0,0.09673268538801975
|
||||
1,Exfiltration,0.5,3,916.0,0.09230431226396064
|
||||
1,Exfiltration,0.5,4,6273.0,0.24155270083748484
|
||||
1,Exfiltration,0.5,5,2759.0,0.16019542325406966
|
||||
1,Exfiltration,0.5,6,2518.0,0.15303899917321462
|
||||
1,Exfiltration,0.5,7,8.0,0.008626194525229437
|
||||
1,Exfiltration,0.5,8,1113.0,0.10174705229246225
|
||||
1,Exfiltration,0.5,9,75.0,0.02641221876100239
|
||||
1,Exfiltration,0.75,0,627.0,0.05728357105623868
|
||||
1,Exfiltration,0.75,1,199.0,0.0242225151235567
|
||||
1,Exfiltration,0.75,2,1006.0,0.0816634858292164
|
||||
1,Exfiltration,0.75,3,916.0,0.07612039507683922
|
||||
1,Exfiltration,0.75,4,6273.0,0.32224478228192666
|
||||
1,Exfiltration,0.75,5,2759.0,0.1740376473264397
|
||||
1,Exfiltration,0.75,6,2518.0,0.1625066818573433
|
||||
1,Exfiltration,0.75,7,8.0,0.002174687802925644
|
||||
1,Exfiltration,0.75,8,1113.0,0.088094907051665
|
||||
1,Exfiltration,0.75,9,75.0,0.01165132659384861
|
||||
1,Exfiltration,1.0,0,627.0,0.04046727765586679
|
||||
1,Exfiltration,1.0,1,199.0,0.012843681425067768
|
||||
1,Exfiltration,1.0,2,1006.0,0.06492835936491545
|
||||
1,Exfiltration,1.0,3,916.0,0.059119659222925
|
||||
1,Exfiltration,1.0,4,6273.0,0.40486639989673423
|
||||
1,Exfiltration,1.0,5,2759.0,0.17806892990835163
|
||||
1,Exfiltration,1.0,6,2518.0,0.16251452175035497
|
||||
1,Exfiltration,1.0,7,8.0,0.000516328901510262
|
||||
1,Exfiltration,1.0,8,1113.0,0.0718342584226152
|
||||
1,Exfiltration,1.0,9,75.0,0.004840583451658707
|
||||
2,Exploitation,0.0,0,56.0,0.1111111111111111
|
||||
2,Exploitation,0.0,2,50.0,0.1111111111111111
|
||||
2,Exploitation,0.0,3,86.0,0.1111111111111111
|
||||
2,Exploitation,0.0,4,46.0,0.1111111111111111
|
||||
2,Exploitation,0.0,5,8.0,0.1111111111111111
|
||||
2,Exploitation,0.0,6,9.0,0.1111111111111111
|
||||
2,Exploitation,0.0,7,46.0,0.1111111111111111
|
||||
2,Exploitation,0.0,8,1.0,0.1111111111111111
|
||||
2,Exploitation,0.0,9,491.0,0.1111111111111111
|
||||
2,Exploitation,0.25,0,56.0,0.1201406619147194
|
||||
2,Exploitation,0.25,2,50.0,0.11678458309217514
|
||||
2,Exploitation,0.25,3,86.0,0.13374194241224655
|
||||
2,Exploitation,0.25,4,46.0,0.1143753593414062
|
||||
2,Exploitation,0.25,5,8.0,0.07386105563289265
|
||||
2,Exploitation,0.25,6,9.0,0.07606828780346402
|
||||
2,Exploitation,0.25,7,46.0,0.1143753593414062
|
||||
2,Exploitation,0.25,8,1.0,0.04391804644012388
|
||||
2,Exploitation,0.25,9,491.0,0.2067347040215659
|
||||
2,Exploitation,0.5,0,56.0,0.11273514564925723
|
||||
2,Exploitation,0.5,2,50.0,0.10652469978734996
|
||||
2,Exploitation,0.5,3,86.0,0.13970583403505477
|
||||
2,Exploitation,0.5,4,46.0,0.10217490265031934
|
||||
2,Exploitation,0.5,5,8.0,0.04260987991493999
|
||||
2,Exploitation,0.5,6,9.0,0.0451946025500978
|
||||
2,Exploitation,0.5,7,46.0,0.10217490265031934
|
||||
2,Exploitation,0.5,8,1.0,0.015064867516699268
|
||||
2,Exploitation,0.5,9,491.0,0.3338151652459622
|
||||
2,Exploitation,0.75,0,56.0,0.09386084897081189
|
||||
2,Exploitation,0.75,2,50.0,0.08621264334249394
|
||||
2,Exploitation,0.75,3,86.0,0.1294843545480138
|
||||
2,Exploitation,0.75,4,46.0,0.0809863510336706
|
||||
2,Exploitation,0.75,5,8.0,0.02181026528528262
|
||||
2,Exploitation,0.75,6,9.0,0.02382458475320683
|
||||
2,Exploitation,0.75,7,46.0,0.0809863510336706
|
||||
2,Exploitation,0.75,8,1.0,0.004585043473531672
|
||||
2,Exploitation,0.75,9,491.0,0.4782495575593181
|
||||
2,Exploitation,1.0,0,56.0,0.07061790668348046
|
||||
2,Exploitation,1.0,2,50.0,0.06305170239596469
|
||||
2,Exploitation,1.0,3,86.0,0.10844892812105927
|
||||
2,Exploitation,1.0,4,46.0,0.058007566204287514
|
||||
2,Exploitation,1.0,5,8.0,0.01008827238335435
|
||||
2,Exploitation,1.0,6,9.0,0.011349306431273645
|
||||
2,Exploitation,1.0,7,46.0,0.058007566204287514
|
||||
2,Exploitation,1.0,8,1.0,0.0012610340479192938
|
||||
2,Exploitation,1.0,9,491.0,0.6191677175283733
|
||||
3,Lateral_movement,0.0,0,2550.0,0.1
|
||||
3,Lateral_movement,0.0,1,3695.0,0.1
|
||||
3,Lateral_movement,0.0,2,818.0,0.1
|
||||
3,Lateral_movement,0.0,3,1239.0,0.1
|
||||
3,Lateral_movement,0.0,4,242.0,0.1
|
||||
3,Lateral_movement,0.0,5,49.0,0.1
|
||||
3,Lateral_movement,0.0,6,8361.0,0.1
|
||||
3,Lateral_movement,0.0,7,4589.0,0.1
|
||||
3,Lateral_movement,0.0,8,396.0,0.1
|
||||
3,Lateral_movement,0.0,9,178.0,0.1
|
||||
3,Lateral_movement,0.25,0,2550.0,0.1211003085961615
|
||||
3,Lateral_movement,0.25,1,3695.0,0.13286598619551734
|
||||
3,Lateral_movement,0.25,2,818.0,0.0911377978662085
|
||||
3,Lateral_movement,0.25,3,1239.0,0.10110625663303405
|
||||
3,Lateral_movement,0.25,4,242.0,0.06721466620617328
|
||||
3,Lateral_movement,0.25,5,49.0,0.04508781866114288
|
||||
3,Lateral_movement,0.25,6,8361.0,0.16295765280822522
|
||||
3,Lateral_movement,0.25,7,4589.0,0.14026190050545512
|
||||
3,Lateral_movement,0.25,8,396.0,0.07602107405963052
|
||||
3,Lateral_movement,0.25,9,178.0,0.06224653846845163
|
||||
3,Lateral_movement,0.5,0,2550.0,0.12946005533478547
|
||||
3,Lateral_movement,0.5,1,3695.0,0.15583783980228746
|
||||
3,Lateral_movement,0.5,2,818.0,0.07332335863139469
|
||||
3,Lateral_movement,0.5,3,1239.0,0.09024047056073208
|
||||
3,Lateral_movement,0.5,4,242.0,0.03988167417574212
|
||||
3,Lateral_movement,0.5,5,49.0,0.017945837798470695
|
||||
3,Lateral_movement,0.5,6,8361.0,0.234420079995533
|
||||
3,Lateral_movement,0.5,7,4589.0,0.173669969070608
|
||||
3,Lateral_movement,0.5,8,396.0,0.05101680902237561
|
||||
3,Lateral_movement,0.5,9,178.0,0.034203905608070934
|
||||
3,Lateral_movement,0.75,0,2550.0,0.12618171141712917
|
||||
3,Lateral_movement,0.75,1,3695.0,0.16664876909744766
|
||||
3,Lateral_movement,0.75,2,818.0,0.05378439105526583
|
||||
3,Lateral_movement,0.75,3,1239.0,0.07343358958802436
|
||||
3,Lateral_movement,0.75,4,242.0,0.02157509927076969
|
||||
3,Lateral_movement,0.75,5,49.0,0.006512359071280791
|
||||
3,Lateral_movement,0.75,6,8361.0,0.3074573967975947
|
||||
3,Lateral_movement,0.75,7,4589.0,0.19605585719761837
|
||||
3,Lateral_movement,0.75,8,396.0,0.031214951724883873
|
||||
3,Lateral_movement,0.75,9,178.0,0.017135874779985513
|
||||
3,Lateral_movement,1.0,0,2550.0,0.11529592621060722
|
||||
3,Lateral_movement,1.0,1,3695.0,0.16706605778360537
|
||||
3,Lateral_movement,1.0,2,818.0,0.0369851245648144
|
||||
3,Lateral_movement,1.0,3,1239.0,0.056020255911742096
|
||||
3,Lateral_movement,1.0,4,242.0,0.010941809467830176
|
||||
3,Lateral_movement,1.0,5,49.0,0.0022154903467920604
|
||||
3,Lateral_movement,1.0,6,8361.0,0.3780349957046616
|
||||
3,Lateral_movement,1.0,7,4589.0,0.20748745309038297
|
||||
3,Lateral_movement,1.0,8,396.0,0.01790477912917665
|
||||
3,Lateral_movement,1.0,9,178.0,0.008048107790387485
|
||||
4,Normal,0.0,0,89253.0,0.1
|
||||
4,Normal,0.0,1,23474.0,0.1
|
||||
4,Normal,0.0,2,60061.0,0.1
|
||||
4,Normal,0.0,3,69735.0,0.1
|
||||
4,Normal,0.0,4,18842.0,0.1
|
||||
4,Normal,0.0,5,1776.0,0.1
|
||||
4,Normal,0.0,6,9668.0,0.1
|
||||
4,Normal,0.0,7,17477.0,0.1
|
||||
4,Normal,0.0,8,260.0,0.1
|
||||
4,Normal,0.0,9,2231.0,0.1
|
||||
4,Normal,0.25,0,89253.0,0.15421903925662245
|
||||
4,Normal,0.25,1,23474.0,0.11044067762482088
|
||||
4,Normal,0.25,2,60061.0,0.1396787781299011
|
||||
4,Normal,0.25,3,69735.0,0.14499231663017753
|
||||
4,Normal,0.25,4,18842.0,0.10453555695398971
|
||||
4,Normal,0.25,5,1776.0,0.05792193046937319
|
||||
4,Normal,0.25,6,9668.0,0.0884741600033457
|
||||
4,Normal,0.25,7,17477.0,0.10258857779473632
|
||||
4,Normal,0.25,8,260.0,0.03582825236264257
|
||||
4,Normal,0.25,9,2231.0,0.06132071077439059
|
||||
4,Normal,0.5,0,89253.0,0.2082761388854636
|
||||
4,Normal,0.5,1,23474.0,0.10681239588140377
|
||||
4,Normal,0.5,2,60061.0,0.17085369909845277
|
||||
4,Normal,0.5,3,69735.0,0.1840998816096602
|
||||
4,Normal,0.5,4,18842.0,0.09569551992004474
|
||||
4,Normal,0.5,5,1776.0,0.029379850890899332
|
||||
4,Normal,0.5,6,9668.0,0.06854825876091125
|
||||
4,Normal,0.5,7,17477.0,0.09216404975621068
|
||||
4,Normal,0.5,8,260.0,0.011241254508049511
|
||||
4,Normal,0.5,9,2231.0,0.03292895068890413
|
||||
4,Normal,0.75,0,89253.0,0.2587802581458785
|
||||
4,Normal,0.75,1,23474.0,0.09503954532267954
|
||||
4,Normal,0.75,2,60061.0,0.19226863535359762
|
||||
4,Normal,0.75,3,69735.0,0.2150562797473768
|
||||
4,Normal,0.75,4,18842.0,0.08059521800192708
|
||||
4,Normal,0.75,5,1776.0,0.01371027752247949
|
||||
4,Normal,0.75,6,9668.0,0.04886146746290477
|
||||
4,Normal,0.75,7,17477.0,0.0761753028341714
|
||||
4,Normal,0.75,8,260.0,0.003244845594082718
|
||||
4,Normal,0.75,9,2231.0,0.016268170014902095
|
||||
4,Normal,1.0,0,89253.0,0.3048497662043125
|
||||
4,Normal,1.0,1,23474.0,0.08017706308897216
|
||||
4,Normal,1.0,2,60061.0,0.20514248045440728
|
||||
4,Normal,1.0,3,69735.0,0.23818469346977392
|
||||
4,Normal,1.0,4,18842.0,0.06435614819470109
|
||||
4,Normal,1.0,5,1776.0,0.0060660502703422745
|
||||
4,Normal,1.0,6,9668.0,0.033021719602291166
|
||||
4,Normal,1.0,7,17477.0,0.059693896720029234
|
||||
4,Normal,1.0,8,260.0,0.0008880478999374951
|
||||
4,Normal,1.0,9,2231.0,0.007620134095232891
|
||||
5,RDOS,0.0,0,4878.0,0.1
|
||||
5,RDOS,0.0,1,95.0,0.1
|
||||
5,RDOS,0.0,2,2816.0,0.1
|
||||
5,RDOS,0.0,3,2508.0,0.1
|
||||
5,RDOS,0.0,4,341.0,0.1
|
||||
5,RDOS,0.0,5,6.0,0.1
|
||||
5,RDOS,0.0,6,47276.0,0.1
|
||||
5,RDOS,0.0,7,20791.0,0.1
|
||||
5,RDOS,0.0,8,13932.0,0.1
|
||||
5,RDOS,0.0,9,6240.0,0.1
|
||||
5,RDOS,0.25,0,4878.0,0.10685785998076136
|
||||
5,RDOS,0.25,1,95.0,0.03991874919463753
|
||||
5,RDOS,0.25,2,2816.0,0.09314385020941883
|
||||
5,RDOS,0.25,3,2508.0,0.09048527413183693
|
||||
5,RDOS,0.25,4,341.0,0.05494581482251136
|
||||
5,RDOS,0.25,5,6.0,0.02001169319705181
|
||||
5,RDOS,0.25,6,47276.0,0.18854117287660088
|
||||
5,RDOS,0.25,7,20791.0,0.15353764253249236
|
||||
5,RDOS,0.25,8,13932.0,0.13891507888064297
|
||||
5,RDOS,0.25,9,6240.0,0.11364286417404601
|
||||
5,RDOS,0.5,0,4878.0,0.09162099667837655
|
||||
5,RDOS,0.5,1,95.0,0.012786035811850421
|
||||
5,RDOS,0.5,2,2816.0,0.06961301423833205
|
||||
5,RDOS,0.5,3,2508.0,0.06569584150494404
|
||||
5,RDOS,0.5,4,341.0,0.024224303741585254
|
||||
5,RDOS,0.5,5,6.0,0.0032132886428106787
|
||||
5,RDOS,0.5,6,47276.0,0.28522952313055794
|
||||
5,RDOS,0.5,7,20791.0,0.18915237691114564
|
||||
5,RDOS,0.5,8,13932.0,0.15483917430831698
|
||||
5,RDOS,0.5,9,6240.0,0.1036254450320805
|
||||
5,RDOS,0.75,0,4878.0,0.06981690248408114
|
||||
5,RDOS,0.75,1,95.0,0.0036397531776229367
|
||||
5,RDOS,0.75,2,2816.0,0.046238497959526094
|
||||
5,RDOS,0.75,3,2508.0,0.04239111882479618
|
||||
5,RDOS,0.75,4,341.0,0.00949172209437759
|
||||
5,RDOS,0.75,5,6.0,0.00045855630336426534
|
||||
5,RDOS,0.75,6,47276.0,0.3834950590544899
|
||||
5,RDOS,0.75,7,20791.0,0.2071027013699195
|
||||
5,RDOS,0.75,8,13932.0,0.1533872740014106
|
||||
5,RDOS,0.75,9,6240.0,0.08397841473041179
|
||||
5,RDOS,1.0,0,4878.0,0.049331027578046784
|
||||
5,RDOS,1.0,1,95.0,0.0009607313693961551
|
||||
5,RDOS,1.0,2,2816.0,0.02847810038125866
|
||||
5,RDOS,1.0,3,2508.0,0.025363308152058492
|
||||
5,RDOS,1.0,4,341.0,0.003448519968043041
|
||||
5,RDOS,1.0,5,6.0,6.067777069870453e-05
|
||||
5,RDOS,1.0,6,47276.0,0.4781003812586592
|
||||
5,RDOS,1.0,7,20791.0,0.21025858843279432
|
||||
5,RDOS,1.0,8,13932.0,0.1408937835623919
|
||||
5,RDOS,1.0,9,6240.0,0.06310488152665271
|
||||
6,Reconnaissance,0.0,0,12996.0,0.1
|
||||
6,Reconnaissance,0.0,1,5840.0,0.1
|
||||
6,Reconnaissance,0.0,2,1842.0,0.1
|
||||
6,Reconnaissance,0.0,3,14852.0,0.1
|
||||
6,Reconnaissance,0.0,4,23967.0,0.1
|
||||
6,Reconnaissance,0.0,5,9632.0,0.1
|
||||
6,Reconnaissance,0.0,6,4475.0,0.1
|
||||
6,Reconnaissance,0.0,7,2025.0,0.1
|
||||
6,Reconnaissance,0.0,8,6536.0,0.1
|
||||
6,Reconnaissance,0.0,9,6996.0,0.1
|
||||
6,Reconnaissance,0.25,0,12996.0,0.11557426335872803
|
||||
6,Reconnaissance,0.25,1,5840.0,0.09462631332339358
|
||||
6,Reconnaissance,0.25,2,1842.0,0.07091385823558452
|
||||
6,Reconnaissance,0.25,3,14852.0,0.11949643350422161
|
||||
6,Reconnaissance,0.25,4,23967.0,0.13468279712303718
|
||||
6,Reconnaissance,0.25,5,9632.0,0.10723531376462318
|
||||
6,Reconnaissance,0.25,6,4475.0,0.08853336438127579
|
||||
6,Reconnaissance,0.25,7,2025.0,0.0726130978586054
|
||||
6,Reconnaissance,0.25,8,6536.0,0.09732775799477392
|
||||
6,Reconnaissance,0.25,9,6996.0,0.09899680045575684
|
||||
6,Reconnaissance,0.5,0,12996.0,0.12887970117234407
|
||||
6,Reconnaissance,0.5,1,5840.0,0.08639449942599037
|
||||
6,Reconnaissance,0.5,2,1842.0,0.04852041223509337
|
||||
6,Reconnaissance,0.5,3,14852.0,0.13777554554880006
|
||||
6,Reconnaissance,0.5,4,23967.0,0.175019527497146
|
||||
6,Reconnaissance,0.5,5,9632.0,0.11095270790280895
|
||||
6,Reconnaissance,0.5,6,4475.0,0.07562688087950485
|
||||
6,Reconnaissance,0.5,7,2025.0,0.050873566252241084
|
||||
6,Reconnaissance,0.5,8,6536.0,0.09139778920981209
|
||||
6,Reconnaissance,0.5,9,6996.0,0.09455936987625915
|
||||
6,Reconnaissance,0.75,0,12996.0,0.13908870708132934
|
||||
6,Reconnaissance,0.75,1,5840.0,0.07633860657711282
|
||||
6,Reconnaissance,0.75,2,1842.0,0.03212934059999074
|
||||
6,Reconnaissance,0.75,3,14852.0,0.15373519339117522
|
||||
6,Reconnaissance,0.75,4,23967.0,0.22011257274836935
|
||||
6,Reconnaissance,0.75,5,9632.0,0.111102018310427
|
||||
6,Reconnaissance,0.75,6,4475.0,0.06252149767879063
|
||||
6,Reconnaissance,0.75,7,2025.0,0.03449477875278175
|
||||
6,Reconnaissance,0.75,8,6536.0,0.0830651064060061
|
||||
6,Reconnaissance,0.75,9,6996.0,0.08741217845401698
|
||||
6,Reconnaissance,1.0,0,12996.0,0.1457587958860937
|
||||
6,Reconnaissance,1.0,1,5840.0,0.06549948968719507
|
||||
6,Reconnaissance,1.0,2,1842.0,0.020659256849968034
|
||||
6,Reconnaissance,1.0,3,14852.0,0.16657507206065433
|
||||
6,Reconnaissance,1.0,4,23967.0,0.2688058680364733
|
||||
6,Reconnaissance,1.0,5,9632.0,0.10802929531970257
|
||||
6,Reconnaissance,1.0,6,4475.0,0.05019010553941746
|
||||
6,Reconnaissance,1.0,7,2025.0,0.022711723735714045
|
||||
6,Reconnaissance,1.0,8,6536.0,0.07330559325265532
|
||||
6,Reconnaissance,1.0,9,6996.0,0.07846479963212616
|
||||
7,Tampering,0.0,0,8.0,0.1111111111111111
|
||||
7,Tampering,0.0,1,1228.0,0.1111111111111111
|
||||
7,Tampering,0.0,2,260.0,0.1111111111111111
|
||||
7,Tampering,0.0,3,91.0,0.1111111111111111
|
||||
7,Tampering,0.0,4,483.0,0.1111111111111111
|
||||
7,Tampering,0.0,5,680.0,0.1111111111111111
|
||||
7,Tampering,0.0,7,618.0,0.1111111111111111
|
||||
7,Tampering,0.0,8,119.0,0.1111111111111111
|
||||
7,Tampering,0.0,9,99.0,0.1111111111111111
|
||||
7,Tampering,0.25,0,8.0,0.046790200953588545
|
||||
7,Tampering,0.25,1,1228.0,0.16469560326700045
|
||||
7,Tampering,0.25,2,260.0,0.11171866840872458
|
||||
7,Tampering,0.25,3,91.0,0.08592959437275875
|
||||
7,Tampering,0.25,4,483.0,0.13042750793401597
|
||||
7,Tampering,0.25,5,680.0,0.14207237541680212
|
||||
7,Tampering,0.25,7,618.0,0.13871695035463072
|
||||
7,Tampering,0.25,8,119.0,0.09189019094870464
|
||||
7,Tampering,0.25,9,99.0,0.0877589083437741
|
||||
7,Tampering,0.5,0,8.0,0.017980251490604452
|
||||
7,Tampering,0.5,1,1228.0,0.22276653609246694
|
||||
7,Tampering,0.5,2,260.0,0.1025032044334467
|
||||
7,Tampering,0.5,3,91.0,0.060641713545164094
|
||||
7,Tampering,0.5,4,483.0,0.1397089838245828
|
||||
7,Tampering,0.5,5,680.0,0.16576972797093445
|
||||
7,Tampering,0.5,7,618.0,0.15803198892360648
|
||||
7,Tampering,0.5,8,119.0,0.06934645250135424
|
||||
7,Tampering,0.5,9,99.0,0.06325114121783987
|
||||
7,Tampering,0.75,0,8.0,0.006480986155468525
|
||||
7,Tampering,0.75,1,1228.0,0.2826326812706583
|
||||
7,Tampering,0.75,2,260.0,0.08821727012693042
|
||||
7,Tampering,0.75,3,91.0,0.040142521414312994
|
||||
7,Tampering,0.75,4,483.0,0.1403731195760649
|
||||
7,Tampering,0.75,5,680.0,0.18142840727962103
|
||||
7,Tampering,0.75,7,618.0,0.16887484359213606
|
||||
7,Tampering,0.75,8,119.0,0.049088959242897044
|
||||
7,Tampering,0.75,9,99.0,0.04276121134191071
|
||||
7,Tampering,1.0,0,8.0,0.002230897936419409
|
||||
7,Tampering,1.0,1,1228.0,0.3424428332403793
|
||||
7,Tampering,1.0,2,260.0,0.07250418293363078
|
||||
7,Tampering,1.0,3,91.0,0.025376464026770774
|
||||
7,Tampering,1.0,4,483.0,0.1346904629113218
|
||||
7,Tampering,1.0,5,680.0,0.18962632459564974
|
||||
7,Tampering,1.0,7,618.0,0.17233686558839934
|
||||
7,Tampering,1.0,8,119.0,0.03318460680423871
|
||||
7,Tampering,1.0,9,99.0,0.027607361963190184
|
||||
8,Weaponization,0.0,0,11526.0,0.1
|
||||
8,Weaponization,0.0,1,2611.0,0.1
|
||||
8,Weaponization,0.0,2,1209.0,0.1
|
||||
8,Weaponization,0.0,3,1647.0,0.1
|
||||
8,Weaponization,0.0,4,917.0,0.1
|
||||
8,Weaponization,0.0,5,1375.0,0.1
|
||||
8,Weaponization,0.0,6,951.0,0.1
|
||||
8,Weaponization,0.0,7,6976.0,0.1
|
||||
8,Weaponization,0.0,8,6913.0,0.1
|
||||
8,Weaponization,0.0,9,10969.0,0.1
|
||||
8,Weaponization,0.25,0,11526.0,0.13739441060301907
|
||||
8,Weaponization,0.25,1,2611.0,0.09478751320998981
|
||||
8,Weaponization,0.25,2,1209.0,0.07819085944838905
|
||||
8,Weaponization,0.25,3,1647.0,0.08447395176979355
|
||||
8,Weaponization,0.25,4,917.0,0.07296956302069034
|
||||
8,Weaponization,0.25,5,1375.0,0.0807467564699872
|
||||
8,Weaponization,0.25,6,951.0,0.07363673785619201
|
||||
8,Weaponization,0.25,7,6976.0,0.12118560338330699
|
||||
8,Weaponization,0.25,8,6913.0,0.12091106619109798
|
||||
8,Weaponization,0.25,9,10969.0,0.13570353804753404
|
||||
8,Weaponization,0.5,0,11526.0,0.1779201650136799
|
||||
8,Weaponization,0.5,1,2611.0,0.08468164794018174
|
||||
8,Weaponization,0.5,2,1209.0,0.057623418014587556
|
||||
8,Weaponization,0.5,3,1647.0,0.06725625246465362
|
||||
8,Weaponization,0.5,4,917.0,0.05018460762438691
|
||||
8,Weaponization,0.5,5,1375.0,0.061452168704738123
|
||||
8,Weaponization,0.5,6,951.0,0.051106498114700416
|
||||
8,Weaponization,0.5,7,6976.0,0.13841689443045152
|
||||
8,Weaponization,0.5,8,6913.0,0.13779045794448722
|
||||
8,Weaponization,0.5,9,10969.0,0.17356788974813298
|
||||
8,Weaponization,0.75,0,11526.0,0.2181935226168662
|
||||
8,Weaponization,0.75,1,2611.0,0.07164535620438116
|
||||
8,Weaponization,0.75,2,1209.0,0.04021634686447464
|
||||
8,Weaponization,0.75,3,1647.0,0.050711107075023125
|
||||
8,Weaponization,0.75,4,917.0,0.03268585833755308
|
||||
8,Weaponization,0.75,5,1375.0,0.04429043196553467
|
||||
8,Weaponization,0.75,6,951.0,0.033590640121105526
|
||||
8,Weaponization,0.75,7,6976.0,0.14972273310126752
|
||||
8,Weaponization,0.75,8,6913.0,0.1487074785967807
|
||||
8,Weaponization,0.75,9,10969.0,0.21023652511701332
|
||||
8,Weaponization,1.0,0,11526.0,0.25559941455626023
|
||||
8,Weaponization,1.0,1,2611.0,0.05790127289661596
|
||||
8,Weaponization,1.0,2,1209.0,0.026810662172351087
|
||||
8,Weaponization,1.0,3,1647.0,0.036523706036279774
|
||||
8,Weaponization,1.0,4,917.0,0.020335299596398633
|
||||
8,Weaponization,1.0,5,1375.0,0.030491861444981595
|
||||
8,Weaponization,1.0,6,951.0,0.021089280170310906
|
||||
8,Weaponization,1.0,7,6976.0,0.15469907304741207
|
||||
8,Weaponization,1.0,8,6913.0,0.1533019913957511
|
||||
8,Weaponization,1.0,9,10969.0,0.24324743868363863
|
||||
|
+46
@@ -0,0 +1,46 @@
|
||||
class_id,class_name,beta,n_contributors,support_min,support_max,support_mean,prototype_norm,reference_norm_beta0,displacement_from_beta0,relative_displacement
|
||||
0,C&C,0.0,9,13,576,222.66666666666666,4.992104138405685,4.992104138405685,0.0,0.0
|
||||
0,C&C,0.25,9,13,576,222.66666666666666,4.852037998238657,4.992104138405685,0.36797724022308037,0.07371185176048838
|
||||
0,C&C,0.5,9,13,576,222.66666666666666,4.742376194761032,4.992104138405685,0.6695589690144707,0.13412359807628252
|
||||
0,C&C,0.75,9,13,576,222.66666666666666,4.65280704661058,4.992104138405685,0.9254131398589358,0.1853753676209332
|
||||
0,C&C,1.0,9,13,576,222.66666666666666,4.577031141286735,4.992104138405685,1.1548168541805874,0.23132867868205137
|
||||
1,Exfiltration,0.0,10,20,5300,1549.4,6.100872138731717,6.100872138731717,0.0,0.0
|
||||
1,Exfiltration,0.25,10,20,5300,1549.4,6.373166160422756,6.100872138731717,0.8237491288550555,0.1350215362858434
|
||||
1,Exfiltration,0.5,10,20,5300,1549.4,6.59429581012542,6.100872138731717,1.3263165170775955,0.21739785507999804
|
||||
1,Exfiltration,0.75,10,20,5300,1549.4,6.750434428594119,6.100872138731717,1.668226550089498,0.27344066752336466
|
||||
1,Exfiltration,1.0,10,20,5300,1549.4,6.8750663990264895,6.100872138731717,1.967235340132892,0.3224514947041411
|
||||
2,Exploitation,0.0,10,1,298,79.3,5.008097566090378,5.008097566090378,0.0,0.0
|
||||
2,Exploitation,0.25,10,1,298,79.3,5.047843612402878,5.008097566090378,0.8603955105014754,0.17180086832316885
|
||||
2,Exploitation,0.5,10,1,298,79.3,5.080358485205799,5.008097566090378,1.5532104750000217,0.3101398194629325
|
||||
2,Exploitation,0.75,10,1,298,79.3,5.1087633771611625,5.008097566090378,2.03138992764355,0.40562107683324844
|
||||
2,Exploitation,1.0,10,1,298,79.3,5.136319248087567,5.008097566090378,2.3385740832421744,0.4669585710702928
|
||||
3,Lateral_movement,0.0,10,11,6341,2211.7,8.481321033671277,8.481321033671277,0.0,0.0
|
||||
3,Lateral_movement,0.25,10,11,6341,2211.7,6.381682682418986,8.481321033671277,2.6907008570910045,0.31725020741565907
|
||||
3,Lateral_movement,0.5,10,11,6341,2211.7,5.888946922739037,8.481321033671277,3.5825998636295417,0.42241059493048755
|
||||
3,Lateral_movement,0.75,10,11,6341,2211.7,5.835315568632712,8.481321033671277,3.841073254381612,0.452886200054491
|
||||
3,Lateral_movement,1.0,10,11,6341,2211.7,5.867438144584891,8.481321033671277,3.9173091599439407,0.46187488298014234
|
||||
4,Normal,0.0,10,79,92031,29277.7,4.799298249108693,4.799298249108693,0.0,0.0
|
||||
4,Normal,0.25,10,79,92031,29277.7,5.712379958571236,4.799298249108693,1.1032890094562697,0.22988548579183807
|
||||
4,Normal,0.5,10,79,92031,29277.7,6.190715393209056,4.799298249108693,1.664815841256164,0.3468873478670235
|
||||
4,Normal,0.75,10,79,92031,29277.7,6.413993120649692,4.799298249108693,1.934162646704862,0.40300947061668174
|
||||
4,Normal,1.0,10,79,92031,29277.7,6.530433735916667,4.799298249108693,2.083642028161429,0.4341555619195775
|
||||
5,RDOS,0.0,10,4,48860,9888.3,6.959683596787167,6.959683596787167,0.0,0.0
|
||||
5,RDOS,0.25,10,4,48860,9888.3,7.618774665376232,6.959683596787167,1.6164653614457636,0.2322613289765041
|
||||
5,RDOS,0.5,10,4,48860,9888.3,7.820301085426912,6.959683596787167,2.353132945001506,0.3381091844588731
|
||||
5,RDOS,0.75,10,4,48860,9888.3,7.86519605437697,6.959683596787167,2.8666348425171084,0.41189154688590257
|
||||
5,RDOS,1.0,10,4,48860,9888.3,7.8810106988442605,6.959683596787167,3.322434234042245,0.4773829424624988
|
||||
6,Reconnaissance,0.0,10,208,22975,8916.1,5.415862180814956,5.415862180814956,0.0,0.0
|
||||
6,Reconnaissance,0.25,10,208,22975,8916.1,5.648965820089017,5.415862180814956,0.4294267183380856,0.07929055504020734
|
||||
6,Reconnaissance,0.5,10,208,22975,8916.1,5.808825260074657,5.415862180814956,0.7413987406482649,0.13689394521053017
|
||||
6,Reconnaissance,0.75,10,208,22975,8916.1,5.916255824906189,5.415862180814956,0.9617371210189529,0.17757784243952732
|
||||
6,Reconnaissance,1.0,10,208,22975,8916.1,5.991685616665521,5.415862180814956,1.1180725676513317,0.20644405827237813
|
||||
7,Tampering,0.0,10,26,2437,358.6,4.705216201871325,4.705216201871325,0.0,0.0
|
||||
7,Tampering,0.25,10,26,2437,358.6,4.639701461060896,4.705216201871325,0.7387359771740888,0.15700362012701646
|
||||
7,Tampering,0.5,10,26,2437,358.6,4.771752454614714,4.705216201871325,1.706873516878616,0.3627619738705674
|
||||
7,Tampering,0.75,10,26,2437,358.6,5.157225192090308,4.705216201871325,2.768796503000988,0.5884525565264784
|
||||
7,Tampering,1.0,10,26,2437,358.6,5.656404611496285,4.705216201871325,3.6982366587327884,0.7859865519594939
|
||||
8,Weaponization,0.0,10,17,23228,4509.4,5.306307987150024,5.306307987150024,0.0,0.0
|
||||
8,Weaponization,0.25,10,17,23228,4509.4,5.843513874965596,5.306307987150024,1.2689737477647698,0.23914438265509075
|
||||
8,Weaponization,0.5,10,17,23228,4509.4,6.216911060615151,5.306307987150024,2.0356955585328023,0.38363690224211017
|
||||
8,Weaponization,0.75,10,17,23228,4509.4,6.441588231782958,5.306307987150024,2.543364318490572,0.4793095924039254
|
||||
8,Weaponization,1.0,10,17,23228,4509.4,6.5954300391115535,5.306307987150024,2.934502391320979,0.5530214978903019
|
||||
|
+446
@@ -0,0 +1,446 @@
|
||||
class_id,class_name,beta,client_id,N_ij,weight
|
||||
0,C&C,0.0,0,576.0,0.1111111111111111
|
||||
0,C&C,0.0,1,290.0,0.1111111111111111
|
||||
0,C&C,0.0,3,211.0,0.1111111111111111
|
||||
0,C&C,0.0,4,37.0,0.1111111111111111
|
||||
0,C&C,0.0,5,252.0,0.1111111111111111
|
||||
0,C&C,0.0,6,212.0,0.1111111111111111
|
||||
0,C&C,0.0,7,13.0,0.1111111111111111
|
||||
0,C&C,0.0,8,296.0,0.1111111111111111
|
||||
0,C&C,0.0,9,117.0,0.1111111111111111
|
||||
0,C&C,0.25,0,576.0,0.15102191422892977
|
||||
0,C&C,0.25,1,290.0,0.12721368978362058
|
||||
0,C&C,0.25,3,211.0,0.1174910983303728
|
||||
0,C&C,0.25,4,37.0,0.0760299633060768
|
||||
0,C&C,0.25,5,252.0,0.12282435299375524
|
||||
0,C&C,0.25,6,212.0,0.11763005906798477
|
||||
0,C&C,0.25,7,13.0,0.05853561531663628
|
||||
0,C&C,0.25,8,296.0,0.12786664719190285
|
||||
0,C&C,0.25,9,117.0,0.10138665978072102
|
||||
0,C&C,0.5,0,576.0,0.19401845748233754
|
||||
0,C&C,0.5,1,290.0,0.1376673031078246
|
||||
0,C&C,0.5,3,211.0,0.11742837022526757
|
||||
0,C&C,0.5,4,37.0,0.04917367513999254
|
||||
0,C&C,0.5,5,252.0,0.12833114706365603
|
||||
0,C&C,0.5,6,212.0,0.11770630758500977
|
||||
0,C&C,0.5,7,13.0,0.02914764570162491
|
||||
0,C&C,0.5,8,296.0,0.1390841565894123
|
||||
0,C&C,0.5,9,117.0,0.08744293710487475
|
||||
0,C&C,0.75,0,576.0,0.23955666553058955
|
||||
0,C&C,0.75,1,290.0,0.14318248489669622
|
||||
0,C&C,0.75,3,211.0,0.11279847762533143
|
||||
0,C&C,0.75,4,37.0,0.030566287230480278
|
||||
0,C&C,0.75,5,252.0,0.12886702493762558
|
||||
0,C&C,0.75,6,212.0,0.1131991830239939
|
||||
0,C&C,0.75,7,13.0,0.013949187470554809
|
||||
0,C&C,0.75,8,296.0,0.14539858501481584
|
||||
0,C&C,0.75,9,117.0,0.07248210426991236
|
||||
0,C&C,1.0,0,576.0,0.2874251497005988
|
||||
0,C&C,1.0,1,290.0,0.14471057884231536
|
||||
0,C&C,1.0,3,211.0,0.10528942115768464
|
||||
0,C&C,1.0,4,37.0,0.018463073852295408
|
||||
0,C&C,1.0,5,252.0,0.12574850299401197
|
||||
0,C&C,1.0,6,212.0,0.10578842315369262
|
||||
0,C&C,1.0,7,13.0,0.006487025948103792
|
||||
0,C&C,1.0,8,296.0,0.14770459081836326
|
||||
0,C&C,1.0,9,117.0,0.058383233532934134
|
||||
1,Exfiltration,0.0,0,2126.0,0.1
|
||||
1,Exfiltration,0.0,1,20.0,0.1
|
||||
1,Exfiltration,0.0,2,914.0,0.1
|
||||
1,Exfiltration,0.0,3,1557.0,0.1
|
||||
1,Exfiltration,0.0,4,30.0,0.1
|
||||
1,Exfiltration,0.0,5,1430.0,0.1
|
||||
1,Exfiltration,0.0,6,5300.0,0.1
|
||||
1,Exfiltration,0.0,7,2362.0,0.1
|
||||
1,Exfiltration,0.0,8,150.0,0.1
|
||||
1,Exfiltration,0.0,9,1605.0,0.1
|
||||
1,Exfiltration,0.25,0,2126.0,0.1245754812136925
|
||||
1,Exfiltration,0.25,1,20.0,0.03879709938306384
|
||||
1,Exfiltration,0.25,2,914.0,0.10087378280431746
|
||||
1,Exfiltration,0.25,3,1557.0,0.11524282917902283
|
||||
1,Exfiltration,0.25,4,30.0,0.04293604842405325
|
||||
1,Exfiltration,0.25,5,1430.0,0.11281731714741136
|
||||
1,Exfiltration,0.25,6,5300.0,0.15653473624097708
|
||||
1,Exfiltration,0.25,7,2362.0,0.12789740466447497
|
||||
1,Exfiltration,0.25,8,150.0,0.06420436768136334
|
||||
1,Exfiltration,0.25,9,1605.0,0.11612093326162334
|
||||
1,Exfiltration,0.5,0,2126.0,0.1367087312207029
|
||||
1,Exfiltration,0.5,1,20.0,0.013259575496658765
|
||||
1,Exfiltration,0.5,2,914.0,0.08963708409730776
|
||||
1,Exfiltration,0.5,3,1557.0,0.11699274444200186
|
||||
1,Exfiltration,0.5,4,30.0,0.016239597086362405
|
||||
1,Exfiltration,0.5,5,1430.0,0.11211988440120217
|
||||
1,Exfiltration,0.5,6,5300.0,0.2158502506905477
|
||||
1,Exfiltration,0.5,7,2362.0,0.14409687724487022
|
||||
1,Exfiltration,0.5,8,150.0,0.036312843012313856
|
||||
1,Exfiltration,0.5,9,1605.0,0.1187824123080323
|
||||
1,Exfiltration,0.75,0,2126.0,0.1398719763694802
|
||||
1,Exfiltration,0.75,1,20.0,0.004225039397957745
|
||||
1,Exfiltration,0.75,2,914.0,0.07426221746657875
|
||||
1,Exfiltration,0.75,3,1557.0,0.11073240327966676
|
||||
1,Exfiltration,0.75,4,30.0,0.005726631097987726
|
||||
1,Exfiltration,0.75,5,1430.0,0.10388678215251898
|
||||
1,Exfiltration,0.75,6,5300.0,0.27750139361661635
|
||||
1,Exfiltration,0.75,7,2362.0,0.15136246307483137
|
||||
1,Exfiltration,0.75,8,150.0,0.019148145134778874
|
||||
1,Exfiltration,0.75,9,1605.0,0.11328294840958317
|
||||
1,Exfiltration,1.0,0,2126.0,0.13721440557635214
|
||||
1,Exfiltration,1.0,1,20.0,0.001290822253775655
|
||||
1,Exfiltration,1.0,2,914.0,0.058990576997547436
|
||||
1,Exfiltration,1.0,3,1557.0,0.10049051245643476
|
||||
1,Exfiltration,1.0,4,30.0,0.0019362333806634826
|
||||
1,Exfiltration,1.0,5,1430.0,0.09229379114495934
|
||||
1,Exfiltration,1.0,6,5300.0,0.3420678972505486
|
||||
1,Exfiltration,1.0,7,2362.0,0.15244610817090487
|
||||
1,Exfiltration,1.0,8,150.0,0.009681166903317414
|
||||
1,Exfiltration,1.0,9,1605.0,0.10358848586549632
|
||||
2,Exploitation,0.0,0,10.0,0.1
|
||||
2,Exploitation,0.0,1,1.0,0.1
|
||||
2,Exploitation,0.0,2,240.0,0.1
|
||||
2,Exploitation,0.0,3,2.0,0.1
|
||||
2,Exploitation,0.0,4,35.0,0.1
|
||||
2,Exploitation,0.0,5,145.0,0.1
|
||||
2,Exploitation,0.0,6,298.0,0.1
|
||||
2,Exploitation,0.0,7,49.0,0.1
|
||||
2,Exploitation,0.0,8,7.0,0.1
|
||||
2,Exploitation,0.0,9,6.0,0.1
|
||||
2,Exploitation,0.25,0,10.0,0.07472353923163849
|
||||
2,Exploitation,0.25,1,1.0,0.042020134074432634
|
||||
2,Exploitation,0.25,2,240.0,0.16539037968734396
|
||||
2,Exploitation,0.25,3,2.0,0.04997064241468357
|
||||
2,Exploitation,0.25,4,35.0,0.10220554181683487
|
||||
2,Exploitation,0.25,5,145.0,0.1458140706954984
|
||||
2,Exploitation,0.25,6,298.0,0.17458683816365086
|
||||
2,Exploitation,0.25,7,49.0,0.11117482481854002
|
||||
2,Exploitation,0.25,8,7.0,0.06834896520487059
|
||||
2,Exploitation,0.25,9,6.0,0.06576506389250662
|
||||
2,Exploitation,0.5,0,10.0,0.046242935423721356
|
||||
2,Exploitation,0.5,1,1.0,0.014623300163104301
|
||||
2,Exploitation,0.5,2,240.0,0.22654319199318068
|
||||
2,Exploitation,0.5,3,2.0,0.020680469417314797
|
||||
2,Exploitation,0.5,4,35.0,0.08651261045713868
|
||||
2,Exploitation,0.5,5,145.0,0.17608785196808927
|
||||
2,Exploitation,0.5,6,298.0,0.25243730010193305
|
||||
2,Exploitation,0.5,7,49.0,0.10236310114173011
|
||||
2,Exploitation,0.5,8,7.0,0.03868961557862425
|
||||
2,Exploitation,0.5,9,6.0,0.03581962375516356
|
||||
2,Exploitation,0.75,0,10.0,0.02512275929612515
|
||||
2,Exploitation,0.75,1,1.0,0.0044675285579663295
|
||||
2,Exploitation,0.75,2,240.0,0.27241170763423844
|
||||
2,Exploitation,0.75,3,2.0,0.007513457498874965
|
||||
2,Exploitation,0.75,4,35.0,0.06428629111250711
|
||||
2,Exploitation,0.75,5,145.0,0.18667808582049356
|
||||
2,Exploitation,0.75,6,298.0,0.32042731849990974
|
||||
2,Exploitation,0.75,7,49.0,0.08273978677620542
|
||||
2,Exploitation,0.75,8,7.0,0.019226085412864014
|
||||
2,Exploitation,0.75,9,6.0,0.017126979390815276
|
||||
2,Exploitation,1.0,0,10.0,0.012610340479192938
|
||||
2,Exploitation,1.0,1,1.0,0.0012610340479192938
|
||||
2,Exploitation,1.0,2,240.0,0.3026481715006305
|
||||
2,Exploitation,1.0,3,2.0,0.0025220680958385876
|
||||
2,Exploitation,1.0,4,35.0,0.044136191677175286
|
||||
2,Exploitation,1.0,5,145.0,0.1828499369482976
|
||||
2,Exploitation,1.0,6,298.0,0.37578814627994955
|
||||
2,Exploitation,1.0,7,49.0,0.0617906683480454
|
||||
2,Exploitation,1.0,8,7.0,0.008827238335435058
|
||||
2,Exploitation,1.0,9,6.0,0.007566204287515763
|
||||
3,Lateral_movement,0.0,0,3084.0,0.1
|
||||
3,Lateral_movement,0.0,1,11.0,0.1
|
||||
3,Lateral_movement,0.0,2,2152.0,0.1
|
||||
3,Lateral_movement,0.0,3,72.0,0.1
|
||||
3,Lateral_movement,0.0,4,566.0,0.1
|
||||
3,Lateral_movement,0.0,5,6341.0,0.1
|
||||
3,Lateral_movement,0.0,6,3130.0,0.1
|
||||
3,Lateral_movement,0.0,7,4431.0,0.1
|
||||
3,Lateral_movement,0.0,8,131.0,0.1
|
||||
3,Lateral_movement,0.0,9,2199.0,0.1
|
||||
3,Lateral_movement,0.25,0,3084.0,0.12702175800740229
|
||||
3,Lateral_movement,0.25,1,11.0,0.031041857299547067
|
||||
3,Lateral_movement,0.25,2,2152.0,0.11609408516022754
|
||||
3,Lateral_movement,0.25,3,72.0,0.0496515317395058
|
||||
3,Lateral_movement,0.25,4,566.0,0.0831387775793627
|
||||
3,Lateral_movement,0.25,5,6341.0,0.15210341508889633
|
||||
3,Lateral_movement,0.25,6,3130.0,0.12749278590878954
|
||||
3,Lateral_movement,0.25,7,4431.0,0.13906728125201873
|
||||
3,Lateral_movement,0.25,8,131.0,0.057665671116614775
|
||||
3,Lateral_movement,0.25,9,2199.0,0.11672283684763529
|
||||
3,Lateral_movement,0.5,0,3084.0,0.13953291328353135
|
||||
3,Lateral_movement,0.5,1,11.0,0.008333277031910022
|
||||
3,Lateral_movement,0.5,2,2152.0,0.1165576038262483
|
||||
3,Lateral_movement,0.5,3,72.0,0.02131992759351566
|
||||
3,Lateral_movement,0.5,4,566.0,0.0597761159716795
|
||||
3,Lateral_movement,0.5,5,6341.0,0.20007754681173798
|
||||
3,Lateral_movement,0.5,6,3130.0,0.14056967669368875
|
||||
3,Lateral_movement,0.5,7,4431.0,0.16725162738364865
|
||||
3,Lateral_movement,0.5,8,131.0,0.028757764639806005
|
||||
3,Lateral_movement,0.5,9,2199.0,0.11782354676423379
|
||||
3,Lateral_movement,0.75,0,3084.0,0.1422829526966925
|
||||
3,Lateral_movement,0.75,1,11.0,0.0020766418694166703
|
||||
3,Lateral_movement,0.75,2,2152.0,0.10862975309362505
|
||||
3,Lateral_movement,0.75,3,72.0,0.008497994868397177
|
||||
3,Lateral_movement,0.75,4,566.0,0.0398960055447025
|
||||
3,Lateral_movement,0.75,5,6341.0,0.24430671665218012
|
||||
3,Lateral_movement,0.75,6,3130.0,0.14387169007556813
|
||||
3,Lateral_movement,0.75,7,4431.0,0.18672110322562685
|
||||
3,Lateral_movement,0.75,8,131.0,0.013312835445965593
|
||||
3,Lateral_movement,0.75,9,2199.0,0.11040430652782546
|
||||
3,Lateral_movement,1.0,0,3084.0,0.13944024958176968
|
||||
3,Lateral_movement,1.0,1,11.0,0.0004973549758104626
|
||||
3,Lateral_movement,1.0,2,2152.0,0.09730071890401049
|
||||
3,Lateral_movement,1.0,3,72.0,0.0032554143871230275
|
||||
3,Lateral_movement,1.0,4,566.0,0.0255911742098838
|
||||
3,Lateral_movement,1.0,5,6341.0,0.28670253651037664
|
||||
3,Lateral_movement,1.0,6,3130.0,0.14152009766243162
|
||||
3,Lateral_movement,1.0,7,4431.0,0.2003436270741963
|
||||
3,Lateral_movement,1.0,8,131.0,0.005923045621015508
|
||||
3,Lateral_movement,1.0,9,2199.0,0.09942578107338247
|
||||
4,Normal,0.0,0,864.0,0.1
|
||||
4,Normal,0.0,1,418.0,0.1
|
||||
4,Normal,0.0,2,79.0,0.1
|
||||
4,Normal,0.0,3,33716.0,0.1
|
||||
4,Normal,0.0,4,10789.0,0.1
|
||||
4,Normal,0.0,5,1541.0,0.1
|
||||
4,Normal,0.0,6,73646.0,0.1
|
||||
4,Normal,0.0,7,57785.0,0.1
|
||||
4,Normal,0.0,8,92031.0,0.1
|
||||
4,Normal,0.0,9,21908.0,0.1
|
||||
4,Normal,0.25,0,864.0,0.05188460739258251
|
||||
4,Normal,0.25,1,418.0,0.04327172113503886
|
||||
4,Normal,0.25,2,79.0,0.028530992000834074
|
||||
4,Normal,0.25,3,33716.0,0.1296788380467858
|
||||
4,Normal,0.25,4,10789.0,0.09753385669084398
|
||||
4,Normal,0.25,5,1541.0,0.059959880532585996
|
||||
4,Normal,0.25,6,73646.0,0.15765123965898994
|
||||
4,Normal,0.25,7,57785.0,0.14837607503612354
|
||||
4,Normal,0.25,8,92031.0,0.16668389274771683
|
||||
4,Normal,0.25,9,21908.0,0.11642889675849852
|
||||
4,Normal,0.5,0,864.0,0.021795608067872552
|
||||
4,Normal,0.5,1,418.0,0.015160036935382743
|
||||
4,Normal,0.5,2,79.0,0.006590610776578489
|
||||
4,Normal,0.5,3,33716.0,0.13615391733129972
|
||||
4,Normal,0.5,4,10789.0,0.07701985826089296
|
||||
4,Normal,0.5,5,1541.0,0.029108071823932803
|
||||
4,Normal,0.5,6,73646.0,0.2012272074670356
|
||||
4,Normal,0.5,7,57785.0,0.17824595265334742
|
||||
4,Normal,0.5,8,92031.0,0.22494647347085892
|
||||
4,Normal,0.5,9,21908.0,0.10975226321279885
|
||||
4,Normal,0.75,0,864.0,0.008234413752433757
|
||||
4,Normal,0.75,1,418.0,0.0047767178535437
|
||||
4,Normal,0.75,2,79.0,0.0013692025418151716
|
||||
4,Normal,0.75,3,33716.0,0.12856549080612478
|
||||
4,Normal,0.75,4,10789.0,0.05469948948624618
|
||||
4,Normal,0.75,5,1541.0,0.01270864818588827
|
||||
4,Normal,0.75,6,73646.0,0.23099854847865048
|
||||
4,Normal,0.75,7,57785.0,0.19257890653203613
|
||||
4,Normal,0.75,8,92031.0,0.2730222139329396
|
||||
4,Normal,0.75,9,21908.0,0.093046368430322
|
||||
4,Normal,1.0,0,864.0,0.0029510514828692143
|
||||
4,Normal,1.0,1,418.0,0.0014277077775918191
|
||||
4,Normal,1.0,2,79.0,0.000269829938827162
|
||||
4,Normal,1.0,3,33716.0,0.11515931920881763
|
||||
4,Normal,1.0,4,10789.0,0.03685057227856013
|
||||
4,Normal,1.0,5,1541.0,0.005263391591552615
|
||||
4,Normal,1.0,6,73646.0,0.2515429832261414
|
||||
4,Normal,1.0,7,57785.0,0.1973686457611083
|
||||
4,Normal,1.0,8,92031.0,0.31433821645826004
|
||||
4,Normal,1.0,9,21908.0,0.0748282822762717
|
||||
5,RDOS,0.0,0,17951.0,0.1
|
||||
5,RDOS,0.0,1,7758.0,0.1
|
||||
5,RDOS,0.0,2,48860.0,0.1
|
||||
5,RDOS,0.0,3,94.0,0.1
|
||||
5,RDOS,0.0,4,1624.0,0.1
|
||||
5,RDOS,0.0,5,1142.0,0.1
|
||||
5,RDOS,0.0,6,4.0,0.1
|
||||
5,RDOS,0.0,7,10129.0,0.1
|
||||
5,RDOS,0.0,8,4382.0,0.1
|
||||
5,RDOS,0.0,9,6939.0,0.1
|
||||
5,RDOS,0.25,0,17951.0,0.14502857687379875
|
||||
5,RDOS,0.25,1,7758.0,0.117589587658176
|
||||
5,RDOS,0.25,2,48860.0,0.18628152700149078
|
||||
5,RDOS,0.25,3,94.0,0.039013362856557
|
||||
5,RDOS,0.25,4,1624.0,0.07953859769224278
|
||||
5,RDOS,0.25,5,1142.0,0.0728363123438262
|
||||
5,RDOS,0.25,6,4.0,0.017719294303109735
|
||||
5,RDOS,0.25,7,10129.0,0.12569646568603307
|
||||
5,RDOS,0.25,8,4382.0,0.10194114727488954
|
||||
5,RDOS,0.25,9,6939.0,0.11435512830987608
|
||||
5,RDOS,0.5,0,17951.0,0.17198442418661095
|
||||
5,RDOS,0.5,1,7758.0,0.11306278550208099
|
||||
5,RDOS,0.5,2,48860.0,0.2837406273058024
|
||||
5,RDOS,0.5,3,94.0,0.01244539600169817
|
||||
5,RDOS,0.5,4,1624.0,0.05172944342275919
|
||||
5,RDOS,0.5,5,1142.0,0.043378831099658635
|
||||
5,RDOS,0.5,6,4.0,0.002567289170851146
|
||||
5,RDOS,0.5,7,10129.0,0.12918975624376042
|
||||
5,RDOS,0.5,8,4382.0,0.08497300555974267
|
||||
5,RDOS,0.5,9,6939.0,0.10692844150703547
|
||||
5,RDOS,0.75,0,17951.0,0.18336531141459259
|
||||
5,RDOS,0.75,1,7758.0,0.09773790520016168
|
||||
5,RDOS,0.75,2,48860.0,0.38856689071177486
|
||||
5,RDOS,0.75,3,94.0,0.0035694112275838435
|
||||
5,RDOS,0.75,4,1624.0,0.03024755073569198
|
||||
5,RDOS,0.75,5,1142.0,0.02322738257067633
|
||||
5,RDOS,0.75,6,4.0,0.00033442265364325624
|
||||
5,RDOS,0.75,7,10129.0,0.11937836417894782
|
||||
5,RDOS,0.75,8,4382.0,0.06368028158230388
|
||||
5,RDOS,0.75,9,6939.0,0.08989247972462366
|
||||
5,RDOS,1.0,0,17951.0,0.18153777696874082
|
||||
5,RDOS,1.0,1,7758.0,0.07845635751342496
|
||||
5,RDOS,1.0,2,48860.0,0.4941193127231172
|
||||
5,RDOS,1.0,3,94.0,0.0009506184076130376
|
||||
5,RDOS,1.0,4,1624.0,0.016423449935782694
|
||||
5,RDOS,1.0,5,1142.0,0.011549002356320096
|
||||
5,RDOS,1.0,6,4.0,4.0451847132469685e-05
|
||||
5,RDOS,1.0,7,10129.0,0.10243418990119636
|
||||
5,RDOS,1.0,8,4382.0,0.044314998533620545
|
||||
5,RDOS,1.0,9,6939.0,0.0701738418130518
|
||||
6,Reconnaissance,0.0,0,1651.0,0.1
|
||||
6,Reconnaissance,0.0,1,208.0,0.1
|
||||
6,Reconnaissance,0.0,2,12985.0,0.1
|
||||
6,Reconnaissance,0.0,3,17154.0,0.1
|
||||
6,Reconnaissance,0.0,4,22975.0,0.1
|
||||
6,Reconnaissance,0.0,5,16770.0,0.1
|
||||
6,Reconnaissance,0.0,6,5123.0,0.1
|
||||
6,Reconnaissance,0.0,7,8929.0,0.1
|
||||
6,Reconnaissance,0.0,8,2708.0,0.1
|
||||
6,Reconnaissance,0.0,9,658.0,0.1
|
||||
6,Reconnaissance,0.25,0,1651.0,0.07374148107073869
|
||||
6,Reconnaissance,0.25,1,208.0,0.04393300617126853
|
||||
6,Reconnaissance,0.25,2,12985.0,0.1234910764123451
|
||||
6,Reconnaissance,0.25,3,17154.0,0.13239343160661676
|
||||
6,Reconnaissance,0.25,4,22975.0,0.14242589843429998
|
||||
6,Reconnaissance,0.25,5,16770.0,0.1316462078006376
|
||||
6,Reconnaissance,0.25,6,5123.0,0.09787148471969809
|
||||
6,Reconnaissance,0.25,7,8929.0,0.11245422928318183
|
||||
6,Reconnaissance,0.25,8,2708.0,0.08345209671284375
|
||||
6,Reconnaissance,0.25,9,658.0,0.05859108778836971
|
||||
6,Reconnaissance,0.5,0,1651.0,0.04926272195084457
|
||||
6,Reconnaissance,0.5,1,208.0,0.0174854387978552
|
||||
6,Reconnaissance,0.5,2,12985.0,0.13815475751236914
|
||||
6,Reconnaissance,0.5,3,17154.0,0.15879161684940787
|
||||
6,Reconnaissance,0.5,4,22975.0,0.18376915905719687
|
||||
6,Reconnaissance,0.5,5,16770.0,0.15700424660659393
|
||||
6,Reconnaissance,0.5,6,5123.0,0.08677748234243855
|
||||
6,Reconnaissance,0.5,7,8929.0,0.11456350164519018
|
||||
6,Reconnaissance,0.5,8,2708.0,0.06309125958277643
|
||||
6,Reconnaissance,0.5,9,658.0,0.03109981565532717
|
||||
6,Reconnaissance,0.75,0,1651.0,0.030840346291550146
|
||||
6,Reconnaissance,0.75,1,208.0,0.006521634300518785
|
||||
6,Reconnaissance,0.75,2,12985.0,0.14484063041988704
|
||||
6,Reconnaissance,0.75,3,17154.0,0.17847730325539155
|
||||
6,Reconnaissance,0.75,4,22975.0,0.22220333914755816
|
||||
6,Reconnaissance,0.75,5,16770.0,0.17547236839271976
|
||||
6,Reconnaissance,0.75,6,5123.0,0.07210281289252812
|
||||
6,Reconnaissance,0.75,7,8929.0,0.10937323511754056
|
||||
6,Reconnaissance,0.75,8,2708.0,0.044698755937912026
|
||||
6,Reconnaissance,0.75,9,658.0,0.015469574244393894
|
||||
6,Reconnaissance,1.0,0,1651.0,0.0185170646358834
|
||||
6,Reconnaissance,1.0,1,208.0,0.002332858536804208
|
||||
6,Reconnaissance,1.0,2,12985.0,0.14563542355962808
|
||||
6,Reconnaissance,1.0,3,17154.0,0.1923935352900932
|
||||
6,Reconnaissance,1.0,4,22975.0,0.25767992732248407
|
||||
6,Reconnaissance,1.0,5,16770.0,0.18808671952983927
|
||||
6,Reconnaissance,1.0,6,5123.0,0.057457857134845955
|
||||
6,Reconnaissance,1.0,7,8929.0,0.10014468209194603
|
||||
6,Reconnaissance,1.0,8,2708.0,0.030372023642624018
|
||||
6,Reconnaissance,1.0,9,658.0,0.007379908255851774
|
||||
7,Tampering,0.0,0,118.0,0.1
|
||||
7,Tampering,0.0,1,371.0,0.1
|
||||
7,Tampering,0.0,2,135.0,0.1
|
||||
7,Tampering,0.0,3,2437.0,0.1
|
||||
7,Tampering,0.0,4,76.0,0.1
|
||||
7,Tampering,0.0,5,132.0,0.1
|
||||
7,Tampering,0.0,6,146.0,0.1
|
||||
7,Tampering,0.0,7,26.0,0.1
|
||||
7,Tampering,0.0,8,64.0,0.1
|
||||
7,Tampering,0.0,9,81.0,0.1
|
||||
7,Tampering,0.25,0,118.0,0.0914906614903368
|
||||
7,Tampering,0.25,1,371.0,0.12182873736373746
|
||||
7,Tampering,0.25,2,135.0,0.09462147373200593
|
||||
7,Tampering,0.25,3,2437.0,0.19503841012134226
|
||||
7,Tampering,0.25,4,76.0,0.08196145582272057
|
||||
7,Tampering,0.25,5,132.0,0.09409136058601118
|
||||
7,Tampering,0.25,6,146.0,0.09649270466577241
|
||||
7,Tampering,0.25,7,26.0,0.06268297534976354
|
||||
7,Tampering,0.25,8,64.0,0.07851475128408372
|
||||
7,Tampering,0.25,9,81.0,0.08327746958422619
|
||||
7,Tampering,0.5,0,118.0,0.07465928078918507
|
||||
7,Tampering,0.5,1,371.0,0.13238224845001956
|
||||
7,Tampering,0.5,2,135.0,0.07985639165881428
|
||||
7,Tampering,0.5,3,2437.0,0.33928961183869
|
||||
7,Tampering,0.5,4,76.0,0.05991693570925297
|
||||
7,Tampering,0.5,5,132.0,0.07896411346733563
|
||||
7,Tampering,0.5,6,146.0,0.08304609697876314
|
||||
7,Tampering,0.5,7,26.0,0.035045275003324286
|
||||
7,Tampering,0.5,8,64.0,0.05498355110805415
|
||||
7,Tampering,0.5,9,81.0,0.06185649499656092
|
||||
7,Tampering,0.75,0,118.0,0.05307060131423309
|
||||
7,Tampering,0.75,1,371.0,0.12530630827033065
|
||||
7,Tampering,0.75,2,135.0,0.05870739760575514
|
||||
7,Tampering,0.75,3,2437.0,0.514143263422916
|
||||
7,Tampering,0.75,4,76.0,0.038155108874919706
|
||||
7,Tampering,0.75,5,132.0,0.05772619755866028
|
||||
7,Tampering,0.75,6,146.0,0.062259717357723954
|
||||
7,Tampering,0.75,7,26.0,0.017067602272501124
|
||||
7,Tampering,0.75,8,64.0,0.03354111405422001
|
||||
7,Tampering,0.75,9,81.0,0.04002268926874002
|
||||
7,Tampering,1.0,0,118.0,0.03290574456218628
|
||||
7,Tampering,1.0,1,371.0,0.10345789180145008
|
||||
7,Tampering,1.0,2,135.0,0.03764640267707752
|
||||
7,Tampering,1.0,3,2437.0,0.6795872838817624
|
||||
7,Tampering,1.0,4,76.0,0.021193530395984383
|
||||
7,Tampering,1.0,5,132.0,0.03680981595092025
|
||||
7,Tampering,1.0,6,146.0,0.04071388733965421
|
||||
7,Tampering,1.0,7,26.0,0.007250418293363078
|
||||
7,Tampering,1.0,8,64.0,0.01784718349135527
|
||||
7,Tampering,1.0,9,81.0,0.022587841606246516
|
||||
8,Weaponization,0.0,0,895.0,0.1
|
||||
8,Weaponization,0.0,1,1014.0,0.1
|
||||
8,Weaponization,0.0,2,23228.0,0.1
|
||||
8,Weaponization,0.0,3,10869.0,0.1
|
||||
8,Weaponization,0.0,4,218.0,0.1
|
||||
8,Weaponization,0.0,5,1570.0,0.1
|
||||
8,Weaponization,0.0,6,17.0,0.1
|
||||
8,Weaponization,0.0,7,2670.0,0.1
|
||||
8,Weaponization,0.0,8,38.0,0.1
|
||||
8,Weaponization,0.0,9,4575.0,0.1
|
||||
8,Weaponization,0.25,0,895.0,0.08582243760083762
|
||||
8,Weaponization,0.25,1,1014.0,0.08854306990947461
|
||||
8,Weaponization,0.25,2,23228.0,0.19370821585254064
|
||||
8,Weaponization,0.25,3,10869.0,0.16021105634310917
|
||||
8,Weaponization,0.25,4,218.0,0.06029193331621394
|
||||
8,Weaponization,0.25,5,1570.0,0.09876885061052997
|
||||
8,Weaponization,0.25,6,17.0,0.03186084700198994
|
||||
8,Weaponization,0.25,7,2670.0,0.11279059873978263
|
||||
8,Weaponization,0.25,8,38.0,0.03895749161753624
|
||||
8,Weaponization,0.25,9,4575.0,0.1290454990079852
|
||||
8,Weaponization,0.5,0,895.0,0.05954631191374364
|
||||
8,Weaponization,0.5,1,1014.0,0.06338147296578088
|
||||
8,Weaponization,0.5,2,23228.0,0.3033536738955772
|
||||
8,Weaponization,0.5,3,10869.0,0.2075095768145407
|
||||
8,Weaponization,0.5,4,218.0,0.02938810596696327
|
||||
8,Weaponization,0.5,5,1570.0,0.07886661054849604
|
||||
8,Weaponization,0.5,6,17.0,0.00820668588741752
|
||||
8,Weaponization,0.5,7,2670.0,0.10284874130321621
|
||||
8,Weaponization,0.5,8,38.0,0.0122697340296214
|
||||
8,Weaponization,0.5,9,4575.0,0.13462908667464316
|
||||
8,Weaponization,0.75,0,895.0,0.035987691170914056
|
||||
8,Weaponization,0.75,1,1014.0,0.039519839730892736
|
||||
8,Weaponization,0.75,2,23228.0,0.41380484518079425
|
||||
8,Weaponization,0.75,3,10869.0,0.2341148165504639
|
||||
8,Weaponization,0.75,4,218.0,0.012477543098555985
|
||||
8,Weaponization,0.75,5,1570.0,0.054854397303363285
|
||||
8,Weaponization,0.75,6,17.0,0.0018412951086240396
|
||||
8,Weaponization,0.75,7,2670.0,0.08169023670182742
|
||||
8,Weaponization,0.75,8,38.0,0.0033660797865626784
|
||||
8,Weaponization,0.75,9,4575.0,0.12234325536800156
|
||||
8,Weaponization,1.0,0,895.0,0.01984742981327893
|
||||
8,Weaponization,1.0,1,1014.0,0.02248636182197188
|
||||
8,Weaponization,1.0,2,23228.0,0.5151017873774781
|
||||
8,Weaponization,1.0,3,10869.0,0.24102984876036723
|
||||
8,Weaponization,1.0,4,218.0,0.004834346032731627
|
||||
8,Weaponization,1.0,5,1570.0,0.0348161617953608
|
||||
8,Weaponization,1.0,6,17.0,0.00037699028695613605
|
||||
8,Weaponization,1.0,7,2670.0,0.059209650951346074
|
||||
8,Weaponization,1.0,8,38.0,0.0008426841708431277
|
||||
8,Weaponization,1.0,9,4575.0,0.10145473898966603
|
||||
|
+143
-15
@@ -3,12 +3,17 @@
|
||||
This is the canonical continuation point for the next agent session. It is written to be
|
||||
readable without prior chat history, terminal scrollback, or git history.
|
||||
|
||||
Last updated: 2026-10-02 (Session 16). Session 16 type: **handoff refresh** — no training, no
|
||||
experiments, no source/model/aggregation change, no proposal content change.
|
||||
Last updated: 2026-10-17 (Session 18). Session 18 type: **repository hygiene and documentation
|
||||
refresh** — no training, no experiments, no source/model/aggregation change, no proposal content
|
||||
change. It committed the previously untracked post-hoc statistical audit and defense-preparation
|
||||
work, codified the prototype-snapshot tracking rule in `.gitignore`, refreshed this handoff and
|
||||
`README.md`, declared `matplotlib` in `pyproject.toml`, and applied three behavior-preserving code
|
||||
nits (docstring fix, device-safe embedding extraction, empty-table guard).
|
||||
|
||||
> **Current state in one line.** The 108-run experimental grid is complete and synthesized; the
|
||||
> thesis proposal Markdown has been finalized and committed. Remaining work is academic writing
|
||||
> and, later, formatting into the university template — not new experiments.
|
||||
> thesis proposal Markdown has been finalized and committed; the post-hoc statistical audit and
|
||||
> robustness/defense-preparation aids are committed. Remaining work is academic writing and, later,
|
||||
> formatting into the university template — not new experiments.
|
||||
|
||||
---
|
||||
|
||||
@@ -80,6 +85,15 @@ It is **frozen** unless academic/supervisor feedback requires revision. It is wr
|
||||
|
||||
- `docs/research/FINAL_EXPERIMENTAL_SYNTHESIS.md` — authoritative six-condition synthesis
|
||||
(RQ1/RQ2/RQ3 answers, threats to validity, contribution, unsupported claims, gap assessment).
|
||||
- `docs/research/ORIGINAL_VS_PROPOSED_DEEP_COMPARISON.md` — paired original-vs-proposed deep
|
||||
comparison (`artifacts/analysis/deepcmp__*.csv`).
|
||||
- `docs/research/POSTHOC_STATISTICAL_AUDIT.md` — exploratory paired statistical audit of the
|
||||
completed grid (`scripts/posthoc_statistical_audit.py`, `artifacts/analysis/posthoc__*.csv`);
|
||||
explicit small-n limits (minimum attainable sign-flip p = 0.25 with three seeds); no
|
||||
significance claims.
|
||||
- `kisikisithesis/ROBUSTNESS_AUDIT_DAN_PERSIAPAN_PENGUJI.md` — robustness audit and examiner
|
||||
Q&A preparation; `kisikisithesis/robustness_checks.py` runs deterministic read-only checks
|
||||
over the actual implementation and persisted snapshots (prints only, writes nothing).
|
||||
- `docs/research/CROSS_DATASET_BETA_ANALYSIS.md` — cross-dataset comparison.
|
||||
- `docs/research/XIIOTID_CROSS_ALPHA_ANALYSIS.md` — X-IIoTID cross-alpha analysis.
|
||||
- `docs/research/5GNIDD_CROSS_ALPHA_ANALYSIS.md` — 5G-NIDD cross-alpha analysis.
|
||||
@@ -143,7 +157,10 @@ These constraints must be respected in every future text (proposal, chapters, sl
|
||||
3. **Later, draft thesis chapters** (starting with Chapter 4) from the final synthesis documents and
|
||||
`artifacts/analysis/final__*` + `artifacts/figures/final/`, obeying `CLAIMS_REGISTER.md` and
|
||||
`CHAPTER4_RESULTS_OUTLINE.md`.
|
||||
4. **No more experiments** unless required by new academic feedback.
|
||||
4. **For defense preparation**, use `kisikisithesis/ROBUSTNESS_AUDIT_DAN_PERSIAPAN_PENGUJI.md`
|
||||
(robustness audit, examiner Q&A, oral cheat sheet) and
|
||||
`docs/research/POSTHOC_STATISTICAL_AUDIT.md`; keep the exploratory-test caveats explicit.
|
||||
5. **No more experiments** unless required by new academic feedback.
|
||||
|
||||
---
|
||||
|
||||
@@ -174,11 +191,20 @@ These constraints must be respected in every future text (proposal, chapters, sl
|
||||
|
||||
## 12. Git state
|
||||
|
||||
- Branch `main`, `HEAD = e27c5a83abcb84ab31c667b4d39d580012fa6f26`, in sync with `origin/main`.
|
||||
- Session 15 commit: `docs: finalize thesis proposal markdown` (four proposal files).
|
||||
- No tracked working-tree changes expected between sessions; only pre-existing untracked
|
||||
`artifacts/analysis/*prototype_snapshot.json` files (94) remain untracked and must not be staged
|
||||
accidentally.
|
||||
- Branch `main`, `HEAD = 34bab45` (`docs: improve readability of PROTEAN comparison figures`);
|
||||
sessions after 16 added the deep paired comparison, the redesigned final figures, and the
|
||||
experiments documentation before this branch.
|
||||
- Session 18 work lives on branch **`chore/posthoc-audit-and-docs-refresh`** (not yet merged or
|
||||
pushed):
|
||||
- `111adb2` `research: add post-hoc statistical audit and defense preparation aids`
|
||||
(posthoc script + doc + 6 CSVs, `kisikisithesis/`, 4 remaining beta0-snapshot effect/weight
|
||||
CSVs, `.gitignore` snapshot rule)
|
||||
- documentation refresh (README, this handoff, `pyproject.toml`, three code nits) — commits
|
||||
after `111adb2` on the same branch.
|
||||
- Prototype-snapshot tracking rule (now explicit in `.gitignore`): the **18 beta0-round-0
|
||||
snapshots and their effect/weight CSVs are tracked**; the remaining ~76 non-beta0 snapshot
|
||||
JSONs (~28 MB, inputs to already-committed displacement tables) stay **untracked** — cited by
|
||||
path in the audit documents, like `results/`. Do not stage them.
|
||||
- `results/` is git-ignored. Do not commit raw datasets, large artifacts, or `results/`.
|
||||
|
||||
## 13. Integrity / important commands
|
||||
@@ -196,12 +222,18 @@ git diff --stat
|
||||
.venv/bin/python scripts/analyze_partition_heterogeneity.py --dataset 5gnidd --alphas 0.25 0.5 0.75
|
||||
.venv/bin/python scripts/analyze_cross_alpha.py --dataset 5gnidd --alphas 0.25 0.5 0.75
|
||||
.venv/bin/python scripts/verify_beta0_equivalence.py --dataset 5gnidd --alpha 0.25 --seeds 0 1 2
|
||||
|
||||
# Post-hoc statistical audit (read-only; writes only posthoc__*.csv)
|
||||
.venv/bin/python scripts/posthoc_statistical_audit.py
|
||||
|
||||
# Deterministic robustness checks (prints only, writes nothing)
|
||||
.venv/bin/python kisikisithesis/robustness_checks.py
|
||||
```
|
||||
|
||||
## 14. Recommended next-session prompt
|
||||
|
||||
```
|
||||
You are continuing the perdalam-protean research repository (Session 17).
|
||||
You are continuing the perdalam-protean research repository (Session 19).
|
||||
|
||||
FIRST, read completely:
|
||||
1. docs/handoff/SESSION_HANDOFF.md
|
||||
@@ -218,14 +250,110 @@ Critical rules:
|
||||
- Beta selection uses validation only; PRIMARY is pooled across clients and seeds.
|
||||
- The 108-run 2-dataset x 3-alpha x 3-seed grid is COMPLETE. Do NOT run new training.
|
||||
- The proposal Markdown is finalized and frozen unless academic feedback requires revision.
|
||||
- Non-beta0 prototype snapshots stay untracked (see .gitignore); do not stage them.
|
||||
|
||||
Context: Session 15 finalized and committed the proposal Markdown
|
||||
(docs/proposal/THESIS_PROPOSAL_DRAFT.md) at HEAD e27c5a8. Session 16 refreshed this handoff.
|
||||
"Optimasi" in the title means empirical beta selection among predefined candidates, not a global
|
||||
optimum. All six conditions are synthesized; no material scientific gap remains (classification A).
|
||||
Context: Session 18 (branch chore/posthoc-audit-and-docs-refresh) committed the previously
|
||||
untracked post-hoc statistical audit (scripts/posthoc_statistical_audit.py,
|
||||
docs/research/POSTHOC_STATISTICAL_AUDIT.md, artifacts/analysis/posthoc__*.csv) and the
|
||||
defense-preparation aids (kisikisithesis/), refreshed the handoff/README, and added matplotlib
|
||||
to pyproject.toml. Sessions after 16 added the deep paired comparison
|
||||
(docs/research/ORIGINAL_VS_PROPOSED_DEEP_COMPARISON.md, deepcmp__*.csv) and the redesigned
|
||||
final figures. "Optimasi" in the title means empirical beta selection among predefined
|
||||
candidates, not a global optimum. All six conditions are synthesized; no material scientific
|
||||
gap remains (classification A). The post-hoc tests are EXPLORATORY ONLY (n=3 seeds; minimum
|
||||
attainable sign-flip p = 0.25); never present them as significance.
|
||||
|
||||
Task: perform the requested writing/formatting or review work using the final synthesis documents
|
||||
and artifacts/analysis/final__*. Obey CLAIMS_REGISTER.md wording, keep all limitations explicit,
|
||||
and do not run training or add inferential tests by default. Use .venv/bin/python. Do not commit
|
||||
or push unless asked.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 15. Addendum (2026-10-29, WIB / UTC+7): 1-thread seed-0 sweep in `results/sweep/`
|
||||
|
||||
This addendum is **separate from the 108-run grid above**, which remains the primary evidence. It
|
||||
records an additional deterministic-threading re-run of seed 0 only. Everything lives in the
|
||||
git-ignored `results/sweep/`; no tracked source, model or aggregation file was changed.
|
||||
|
||||
- **What ran:** 30 runs = 2 datasets x 3 alpha (0.25/0.5/0.75) x 5 beta, seed 0, 1 thread per
|
||||
process, pool P=3. Relaunched 2026-10-27T01:13Z (08:13 WIB); last run finished
|
||||
2026-10-28T18:00Z (2026-10-29 01:00 WIB). 30/30 `completed exit 0`, 30 `COMPLETE` markers,
|
||||
0 failed, retry pass was a no-op, `PHASE=done`.
|
||||
- **Gate deadlock (fixed):** `reference_check.py` read a wrong JSON key
|
||||
(`val_rare_macro_f1_per_client_mean` instead of `val_rare_class_macro_f1_per_client_mean`), so the
|
||||
gate never resolved. After the fix the reference check PASSED (max difference to the manual verdict
|
||||
4.3e-10). Details, diffs and raw numbers: `results/sweep/relaunch_report.md` (untracked).
|
||||
- **One journal line to keep open:** `Oct 28 12:11:37 systemd[2118]: -.slice: A process of this unit
|
||||
has been killed by the OOM killer` (host-local time, UTC+1 inferred from file mtimes, i.e.
|
||||
18:11 WIB). The killed process is unidentified; no run scope failed and all 30 runs completed, so
|
||||
it is probably not a training process (inference, not verified).
|
||||
- **Analysis script:** `results/sweep/analyze_sweep.py` (read-only, deterministic; re-running it
|
||||
reproduced all three CSVs byte-identically). Stage 1 selects beta from validation only
|
||||
(`val_rare_class_macro_f1_per_client_mean`, tie -> smaller beta) and is written before any test
|
||||
file is opened. Outputs in `results/sweep/analysis/`: `selection.csv`,
|
||||
`test_at_selected_beta.csv`, `repro_vs_previous.csv`.
|
||||
- **Status of this selection:** it is a **single-seed, per-seed diagnostic**. The primary thesis
|
||||
selection remains pooled validation across clients and seeds (section 6, item 9).
|
||||
|
||||
Validation-selected beta (seed 0) and test rare-class macro-F1 (global) afterwards:
|
||||
|
||||
| dataset | alpha | selected beta | val margin to runner-up | test @ selected | test @ beta 0 |
|
||||
|---|---|---|---|---|---|
|
||||
| X-IIoTID | 0.25 | 0.75 | 0.0413 | 0.6692 | 0.6420 |
|
||||
| X-IIoTID | 0.50 | 0.50 | 0.0074 | 0.6439 | 0.6131 |
|
||||
| X-IIoTID | 0.75 | 0.50 | 0.0004 | 0.5068 | 0.5263 |
|
||||
| 5G-NIDD | 0.25 | 0.25 | 0.0155 | 0.8876 | 0.8612 |
|
||||
| 5G-NIDD | 0.50 | 0.75 | 0.0053 | 0.8793 | 0.8694 |
|
||||
| 5G-NIDD | 0.75 | 0.25 | 0.0132 | 0.9065 | 0.9024 |
|
||||
|
||||
- **Reproducibility caveat (important):** the 1-thread re-run is **not bit-identical** to the earlier
|
||||
grid for the same (dataset, alpha, seed 0, beta). Over 30 pairs the absolute test rare-F1
|
||||
difference has median 0.0022 and max 0.0127 (5G-NIDD alpha 0.5 beta 0.75); the validation
|
||||
selection metric differs by median 0.0029, max 0.0328; 0 of 30 pairs are exactly equal. Compared
|
||||
with the median validation difference (0.0029), only X-IIoTID alpha 0.75 (margin 0.0004) is
|
||||
clearly inside the noise. X-IIoTID alpha 0.5 (0.0074) and 5G-NIDD alpha 0.5 (0.0053) are above
|
||||
the median but well below the max, so they are also not clearly separated. The other three
|
||||
margins (0.0132 to 0.0413) are larger than the median difference; the max difference (0.0328)
|
||||
still exceeds all but the X-IIoTID alpha 0.25 margin. None of this is a significance test.
|
||||
- **Comparison with the 108-run grid** (`results/sweep/compare_with_grid.py` ->
|
||||
`results/sweep/analysis/compare_with_grid.csv`, validation only, no test file opened):
|
||||
the sweep's seed-0 beta equals the grid's seed-0 beta in 4/6 conditions (all three X-IIoTID,
|
||||
plus 5G-NIDD alpha 0.25). The two differences are both 5G-NIDD: alpha 0.5 (sweep 0.75, grid
|
||||
seed-0 1.0; sweep pick is rank 3 in the grid ranking) and alpha 0.75 (sweep 0.25, grid 0.5;
|
||||
rank 4). These two conditions also have the largest per-beta validation differences
|
||||
(0.0328 and 0.0262). The sweep beta equals the grid **pooled** beta in only 1/6, but the grid's
|
||||
own seed-0 beta equals its pooled beta in only 3/6, so a seed-0 vs pooled mismatch is expected
|
||||
and is not a reproducibility measure.
|
||||
- **Not done:** no inferential test; thread count as the cause of the difference is a hypothesis, not
|
||||
verified; the metric files were not cross-checked beyond what `analyze_sweep.py` reads.
|
||||
- **Noise checks** (`results/sweep/check_noise.py` -> `analysis/noise_checks.json`, no training):
|
||||
all 30 pairs already differ at round 0 with identical sample counts; test rare-F1 differences
|
||||
scatter around zero (14 higher / 16 lower, mean signed -0.0004, mean absolute 0.0034); 5G-NIDD is
|
||||
about 2.7x noisier than X-IIoTID on the validation metric; beta-ranking Spearman is 0.30 / 0.50
|
||||
for 5G-NIDD alpha 0.75 / 0.5 and >= 0.90 elsewhere. Thread count remains **unproven and
|
||||
confounded** with host (8 threads / 29 GiB documented earlier vs 12 / 48 GiB now), possibly a
|
||||
different PyTorch version (not recorded in metadata), and a different checkout path. A sign test
|
||||
(p = 0.86 / 1.0) is reported only descriptively because the pairs are not independent.
|
||||
- **Write-up:** `docs/research/SWEEP_1THREAD_SEED0_CHECK.md` (committed in `ad203eb`; section 3.6
|
||||
was added afterwards and is uncommitted) summarizes the sweep, the grid-vs-sweep difference,
|
||||
the noise checks and the comparison above.
|
||||
- **Repeat / multi-thread test** (`results/sweep_repro/`, X-IIoTID alpha 0.25 seed 0 beta 0 only):
|
||||
a 1-thread repeat is bit-identical to the sweep run (all result JSON and the prototype
|
||||
snapshot), so the 1-thread sweep has no run-to-run noise. An 8-thread run on this host differs
|
||||
from the 1-thread run (test rare-F1 1.9e-3) and also does not reproduce the old grid (2.5e-3).
|
||||
Thread count changes results but does not explain the whole grid-vs-sweep difference; host and
|
||||
PyTorch version remain uncontrolled. The same test was also run on 5G-NIDD alpha 0.5 beta 0.75
|
||||
(the largest disagreement): the 1-thread repeat is again bit-identical to the sweep, and the
|
||||
8-thread run again reproduces neither (closer to the sweep on test rare-F1, closer to the grid
|
||||
on the validation metric). Still untested: an 8-thread repeat (its own stability).
|
||||
- **Exact next task:** decide with the user whether the 5G-NIDD alpha 0.5 / 0.75 disagreement
|
||||
warrants an 8-thread repeat (is the multi-thread setup itself stable?) and whether to commit
|
||||
section 3.7. Do not change the primary pooled selection on the basis of this single-seed re-run.
|
||||
- **Housekeeping:** the tmux session `sweep` still exists (windows `control`, `pool`); the
|
||||
`heartbeat` window was stopped on 2026-10-29. Backups of edited sweep scripts are `*.bak` in
|
||||
`results/sweep/`; orphaned attempt-1 artifacts are in `results/sweep/_orphans_20261027T011213Z/`.
|
||||
rsync destination was never specified and rsync was never run.
|
||||
- **Git:** this addendum is an uncommitted edit on branch `chore/posthoc-audit-and-docs-refresh`;
|
||||
nothing was committed or pushed.
|
||||
@@ -0,0 +1,335 @@
|
||||
# Post-hoc Statistical Audit of the PROTEAN Experiment Grid
|
||||
|
||||
Status: **read-only post-hoc audit of completed experiments.** No training, no partition
|
||||
regeneration, no modification of any existing result, manifest, dataset, configuration, source
|
||||
file, or test. All numbers below are recomputed from the audited artifacts by
|
||||
`scripts/posthoc_statistical_audit.py`, which writes new `posthoc__*.csv` tables under
|
||||
`artifacts/analysis/` and refuses to overwrite existing files.
|
||||
|
||||
Scope: determine what the completed 108-run grid can and cannot support statistically, and
|
||||
provide transparent, reusable wording for the thesis limitations.
|
||||
|
||||
---
|
||||
|
||||
## 1. Executive findings
|
||||
|
||||
1. **The comparison is valid and paired.** All 18 `(dataset, alpha, seed)` cells pair the
|
||||
`original_protean` run with the validation-selected `support_weighted` run on an identical
|
||||
`manifest_content_hash`, split, and seed (`posthoc__paired_global_per_seed.csv`,
|
||||
`pairing_verified = True` for every row).
|
||||
2. **The paired differences are small and mostly seed-inconsistent.** For test rare-class
|
||||
macro-F1, only **X-IIoTID α=0.50** has all three seed differences in the same direction
|
||||
(**+0.0230** mean; paired-difference sample std **0.0058**); the other five conditions have
|
||||
mixed-sign seed differences.
|
||||
3. **No condition can reach statistical significance with three seeds.** The smallest attainable
|
||||
two-sided exact sign-flip p-value with three nonzero differences is **0.25**, and only
|
||||
X-IIoTID α=0.50 attains it. This is a **power/design limit**, not evidence of no effect.
|
||||
4. **The paired-difference variability is not the group variability.** At X-IIoTID α=0.50 the
|
||||
baseline and proposed cross-seed std are **0.0287** and **0.0267**, while the paired-difference
|
||||
std is **0.0058** — shared seed-to-seed variation cancels in the paired difference.
|
||||
5. **Selected beta is weakly separated and unstable across seeds.** The best-vs-second margin is
|
||||
only **0.0024–0.0122**, and the pooled selection agrees with at most **2 of 3** seeds in every
|
||||
condition (`posthoc__selection_stability.csv`).
|
||||
6. **The `S_j` participant rule is materially exercised**: `|S_j| < M` in **53 of 162**
|
||||
class-condition cells (verified). This is an implementation/reproduction assumption, not an
|
||||
ordinary statistical limitation.
|
||||
7. **Publication metrics could not be verified** because the referenced `journal/main.tex`
|
||||
(and the paper's Table IV) is **not present in this repository**. Reproduced baseline
|
||||
accuracies are reported instead; the discrepancy figures remain unverified.
|
||||
|
||||
---
|
||||
|
||||
## 2. Data sources and pairing validation
|
||||
|
||||
Primary sources (all committed, read-only):
|
||||
|
||||
| Purpose | Artifact |
|
||||
|---|---|
|
||||
| Paired per-seed global metrics | `artifacts/analysis/deepcmp__global_per_seed.csv` |
|
||||
| Per-run source of truth | `results/<run>/test_global_metrics.json`, `metadata.json` |
|
||||
| Validation per-seed / pooled | `artifacts/analysis/<ds>__alpha*__multiseed__validation_per_seed.csv`, `..._validation_pooled.csv`, `..._selection_summary.json` |
|
||||
| Selection margins | `artifacts/analysis/final__selection_strength.csv`, `final__pooled_validation_curves.csv` |
|
||||
| Per-class | `results/<run>/test_per_class.csv` → `deepcmp__per_class.csv` |
|
||||
| Per-client | `results/<run>/per_client.csv` → `deepcmp__per_client.csv` |
|
||||
| `S_j` rule | `artifacts/analysis/sj_participant_rule_analysis.csv` |
|
||||
| Reproduced baseline metrics | `docs/baseline/BASELINE_VALIDATION.md` |
|
||||
|
||||
Pairing rule enforced in the script: same `dataset`, `alpha`, `seed`, identical
|
||||
`manifest_content_hash`, and recorded `beta == validation-selected beta`. Result: **18/18 cells
|
||||
verified**, written with `pairing_verified` and the manifest hash into
|
||||
`posthoc__paired_global_per_seed.csv`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Descriptive paired results by condition
|
||||
|
||||
Test split, `delta = proposed_selected_beta − original_protean`, three paired seeds per condition.
|
||||
Source: `posthoc__paired_global_by_condition.csv`. The standard deviations below are three distinct
|
||||
quantities: `base_std` and `prop_std` are the cross-seed spread within each group, `paired_std` is
|
||||
computed directly from the three matched differences.
|
||||
|
||||
### 3.1 Rare-class macro-F1 (primary comparison)
|
||||
|
||||
| Dataset | alpha | beta* | Δ seed 0 | Δ seed 1 | Δ seed 2 | mean Δ | paired std | base std | prop std | +/−/0 | same sign |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| X-IIoTID | 0.25 | 0.00 | +0.0016 | −0.0020 | −0.0016 | −0.0007 | 0.0019 | 0.0472 | 0.0476 | 1/2/0 | no |
|
||||
| X-IIoTID | 0.50 | 0.75 | +0.0266 | +0.0163 | +0.0261 | **+0.0230** | 0.0058 | 0.0287 | 0.0267 | 3/0/0 | **yes** |
|
||||
| X-IIoTID | 0.75 | 0.50 | −0.0097 | +0.0101 | +0.0036 | +0.0014 | 0.0101 | 0.0778 | 0.0855 | 2/1/0 | no |
|
||||
| 5G-NIDD | 0.25 | 0.00 | −0.0050 | −0.0010 | +0.0029 | −0.0010 | 0.0039 | 0.0254 | 0.0242 | 1/2/0 | no |
|
||||
| 5G-NIDD | 0.50 | 1.00 | +0.0090 | −0.0811 | +0.0464 | −0.0086 | 0.0655 | 0.0371 | 0.0285 | 2/1/0 | no |
|
||||
| 5G-NIDD | 0.75 | 0.50 | −0.0011 | +0.0450 | +0.0067 | +0.0168 | 0.0247 | 0.0231 | 0.0145 | 2/1/0 | no |
|
||||
|
||||
**Verification of the reported `+0.0230`.** Source `final__six_condition_master.csv`
|
||||
(row X-IIoTID α=0.50): original rare-F1 mean 0.642520 (std **0.028683**), selected-beta mean
|
||||
0.665503 (std **0.026685**), difference **+0.022983**. The paired-difference std computed directly
|
||||
from the three matched seed differences is **0.0058**. The value is exact.
|
||||
|
||||
**What this does and does not establish.** X-IIoTID α=0.50 is the only condition where the
|
||||
improvement appears at every seed, and only there is the paired difference small relative to its own
|
||||
mean. It does **not** establish statistical significance (see §4), and it does not generalize: the
|
||||
same beta direction fails at 5G-NIDD α=0.50 and is mixed at four other conditions.
|
||||
|
||||
### 3.2 Other metrics
|
||||
|
||||
All five metrics (rare-class macro-F1, rare-class recall, macro-F1, weighted-F1, accuracy) with the
|
||||
same columns, including per-metric positive/negative/zero counts and sign agreement, are in
|
||||
`posthoc__paired_global_by_condition.csv`. Highlights:
|
||||
|
||||
- **Rare-class recall** is negative in **5 of 6** conditions (and in **all four** `beta>0`
|
||||
conditions): the rare-class F1 gains are precision-driven.
|
||||
- **Overall macro-F1** moves in the same direction as rare-class F1 in every condition, but its
|
||||
paired differences are equally seed-inconsistent.
|
||||
- **5G-NIDD α=0.50** has a paired-difference std of **0.0655**, larger than either group std,
|
||||
because the three seed differences have mixed sign (one large negative).
|
||||
|
||||
---
|
||||
|
||||
## 4. Inferential analysis and limitations
|
||||
|
||||
Sources: `posthoc__paired_test_results.csv`. Only three paired seeds exist per condition.
|
||||
|
||||
| Dataset | alpha | beta* | exact sign-flip p (2-sided) | exact Wilcoxon p (2-sided) | paired-t 95% CI | min attainable sign-flip p |
|
||||
|---|---|---|---|---|---|---|
|
||||
| X-IIoTID | 0.25 | 0.00 | 0.75 | 1.00 | [−0.0054, +0.0041] | 0.25 |
|
||||
| X-IIoTID | 0.50 | 0.75 | **0.25** | 0.50 | [+0.0085, +0.0374] | 0.25 |
|
||||
| X-IIoTID | 0.75 | 0.50 | 0.75 | 1.00 | [−0.0236, +0.0264] | 0.25 |
|
||||
| 5G-NIDD | 0.25 | 0.00 | 0.75 | 1.00 | [−0.0108, +0.0087] | 0.25 |
|
||||
| 5G-NIDD | 0.50 | 1.00 | 1.00 | 1.00 | [−0.1713, +0.1542] | 0.25 |
|
||||
| 5G-NIDD | 0.75 | 0.50 | 0.50 | 1.00 | [−0.0444, +0.0781] | 0.25 |
|
||||
|
||||
Test definitions and assumptions:
|
||||
|
||||
- **Exact sign-flip permutation test** on the mean of the paired differences. Assumption: under the
|
||||
null the sign of each paired difference is exchangeable. With `n = 3`, the null has `2^3 = 8`
|
||||
sign vectors, so the smallest attainable two-sided p-value is `2/8 = 0.25`; this was verified by
|
||||
enumeration, not assumed.
|
||||
- **Exact Wilcoxon signed-rank** (average ranks for ties, zero differences dropped, exact null by
|
||||
enumerating `2^n` sign assignments, two-sided min-rank convention). At `n = 3` the exact p-values
|
||||
are coarse (0.50 or 1.00), so this test adds little.
|
||||
- **Paired-t 95% CI** using `t = 4.3027` (df = 2). This is an explicitly assumption-dependent,
|
||||
underpowered summary; it is not a reliable interval estimate for a population.
|
||||
|
||||
Interpretation rules applied:
|
||||
|
||||
- **No condition is statistically significant**, and none can be with three seeds.
|
||||
- **Non-significance is not evidence of no effect**; it reflects a sample far too small to resolve
|
||||
effects of this size.
|
||||
- Tests are **not** pooled across the six conditions (they are not replicates of one condition) nor
|
||||
across clients (clients are nested in the same trained model and seed).
|
||||
- Bootstrap CIs are deliberately **not** used: three seeds cannot support a reliable resampling
|
||||
distribution.
|
||||
|
||||
Conclusion: **prioritize descriptive reporting** (values, direction, seed consistency) over
|
||||
inferential claims for this grid.
|
||||
|
||||
---
|
||||
|
||||
## 5. Beta-selection stability
|
||||
|
||||
Source: `posthoc__selection_stability.csv`; per-seed selections are computed from each condition's
|
||||
`validation_per_seed.csv` (per-client-mean validation rare-class macro-F1).
|
||||
|
||||
| Dataset | alpha | pooled beta | per-seed beta (s0/s1/s2) | agree with pooled | best score | 2nd-best (beta, score) | margin | candidate range |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| X-IIoTID | 0.25 | 0.00 | 0.75 / 0.50 / 0.00 | 1/3 | 0.5917 | 0.25, 0.5887 | 0.0030 | 0.0596 |
|
||||
| X-IIoTID | 0.50 | 0.75 | 0.50 / 1.00 / 0.75 | 1/3 | 0.5794 | 1.00, 0.5735 | 0.0059 | 0.0350 |
|
||||
| X-IIoTID | 0.75 | 0.50 | 0.50 / 0.50 / 0.00 | 2/3 | 0.4767 | 0.25, 0.4744 | 0.0024 | 0.0081 |
|
||||
| 5G-NIDD | 0.25 | 0.00 | 0.25 / 0.00 / 0.00 | 2/3 | 0.7615 | 0.25, 0.7493 | 0.0122 | 0.0392 |
|
||||
| 5G-NIDD | 0.50 | 1.00 | 1.00 / 0.00 / 1.00 | 2/3 | 0.6924 | 0.75, 0.6884 | 0.0040 | 0.0473 |
|
||||
| 5G-NIDD | 0.75 | 0.50 | 0.50 / 1.00 / 1.00 | 1/3 | 0.8091 | 1.00, 0.8043 | 0.0048 | 0.0310 |
|
||||
|
||||
Verification: the reported selection margins of **0.0024–0.0122** are confirmed exactly.
|
||||
|
||||
**Interpretation.** A margin of 0.002–0.012 is small relative to both the candidate-score range
|
||||
(0.008–0.060) and the across-seed std of the selected beta (0.022–0.139 in earlier analyses), and the
|
||||
pooled selection agrees with only 1–2 of 3 seeds. This makes the selection **fragile / weakly
|
||||
separated**: it should be described as "best among the tested candidates under the pooled validation
|
||||
procedure", **not** as an optimal or robust choice. A small margin does **not** prove the selected
|
||||
beta is wrong; it means the data cannot discriminate among close candidates. All selections remain
|
||||
**validation-only** (`test_used_for_selection = False`); test metrics are never used to select beta.
|
||||
|
||||
---
|
||||
|
||||
## 6. `S_j` participant-rule audit
|
||||
|
||||
Source: `artifacts/analysis/sj_participant_rule_analysis.csv` (162 class-condition cells = 18
|
||||
condition-seeds × 9 classes). Verified: **`|S_j| < M` in 53 / 162 cells** (X-IIoTID 19/7/3 and
|
||||
5G-NIDD 16/4/4 for α = 0.25/0.50/0.75); all 53 are exactly the cells with ≥1 missing client
|
||||
(`missing_clients` non-empty). `S_j` is the set of clients with `N_ij > 0` and a valid prototype.
|
||||
|
||||
**Why this is an implementation/reproduction assumption, not an ordinary statistical limitation.**
|
||||
Eq. (2)/(5.5) of the source paper sums over `M` clients but is silent on `N_ij = 0`; no official
|
||||
implementation exists (see `docs/baseline/PROTEAN_BASELINE_INVESTIGATION.md`). The project therefore
|
||||
*froze* `S_j = {i : N_ij > 0 and C_ij exists}` and used equal `1/|S_j|` weights in the baseline. In
|
||||
`53/162` cells the literal `1/M` reading (e.g. substituting a zero vector for an absent prototype)
|
||||
would differ from the `S_j` reading, so all results are **conditional on this rule**. More seeds
|
||||
would not remove this; only the (unavailable) official code, or a documented threat/robustness
|
||||
analysis across alternative participant rules, could.
|
||||
|
||||
---
|
||||
|
||||
## 7. Baseline reproduction discrepancy audit
|
||||
|
||||
**Reproduced baseline metrics available in this repository**
|
||||
(`docs/baseline/BASELINE_VALIDATION.md`, and `final__six_condition_master.csv`):
|
||||
|
||||
| Evidence | Value |
|
||||
|---|---|
|
||||
| X-IIoTID α=0.50 seed 0 accuracy | 0.8904 (macro-F1 0.7077, rare-F1 0.6096) |
|
||||
| 5G-NIDD α=0.50 seed 0 accuracy | 0.7344 (macro-F1 0.8369, rare-F1 0.8720) |
|
||||
| X-IIoTID original accuracy means (α=0.25/0.50/0.75) | 0.8754 / 0.8995 / 0.9206 |
|
||||
| 5G-NIDD original accuracy means (α=0.25/0.50/0.75) | 0.7310 / 0.7440 / 0.7510 |
|
||||
|
||||
**Unresolved data gap.** The task's comparison uses the paper's reported metrics ("Table IV") in
|
||||
`journal/main.tex`. That file and directory **do not exist in this repository**, and no file records
|
||||
the paper's numeric accuracy/F1 table (the baseline investigation records only that the paper reports
|
||||
"macro accuracy, accuracy, F1, precision", without values). Therefore the claimed deviations
|
||||
(X-IIoTID ≈ 5.1–9.7 percentage points below the paper; 5G-NIDD ≈ 4.6–8.4 percentage points above the
|
||||
paper) **could not be verified** here. Per the constraints, this is documented as a gap rather than
|
||||
reconstructed.
|
||||
|
||||
**Classification.** Requires the external source (`journal/main.tex` / the published paper and
|
||||
thesis). Even once sourced, such deviations must be reported as **reproduction differences**, not as
|
||||
automatic evidence of an implementation bug: metric definitions, train/test split (the project uses
|
||||
70/10/20 stratified, the paper 80/20), class handling (one dropped class on X-IIoTID), seed
|
||||
initialization, and nearest-prototype inference all differ from the paper and can move accuracy
|
||||
independently of any defect. No defect is claimed.
|
||||
|
||||
---
|
||||
|
||||
## 8. Metric-selection versus headline-metric audit
|
||||
|
||||
Traced in code:
|
||||
|
||||
- **Selection metric** (`scripts/run_baseline.py`, line ~303): `val_rare_class_macro_f1_per_client_mean`
|
||||
— the mean over eligible clients of each client's own validation rare-class macro-F1. Pooled
|
||||
selection across seeds uses this (`scripts/analyze_multiseed_beta.py`).
|
||||
- **Headline test metric**: `test_rare_class_macro_f1` from `rare_class_metrics(test_labels, test_pred,
|
||||
num_classes, union_rare)` — a **global** rare-class macro-F1 pooled over the union of client rare
|
||||
classes.
|
||||
|
||||
**Consequence.** The method is *selected* on a **per-client-mean validation** rare-class macro-F1 but
|
||||
*reported* on a **global test** rare-class macro-F1. These are not the same estimator: the per-client
|
||||
mean weights every client equally (and can be dominated by small clients), whereas the global metric
|
||||
weights by evaluation support. A beta that is best under the selection criterion need not be best
|
||||
under the reported criterion. The two quantities are therefore reported separately in this thesis
|
||||
(validation selection tables vs test evaluation tables) and must never be conflated; neither uses the
|
||||
test set for selection.
|
||||
|
||||
---
|
||||
|
||||
## 9. What can and cannot be concluded
|
||||
|
||||
**Supported by the evidence.**
|
||||
|
||||
- The comparison is a valid paired design with verified common manifests and splits.
|
||||
- Test rare-class macro-F1 changes are **small (≤ ~0.023)** and **condition-dependent**; only
|
||||
X-IIoTID α=0.50 improves in all three seeds.
|
||||
- Rare-class recall tends to fall when rare-class F1 rises (precision–recall trade-off).
|
||||
- The validation-selected beta is **weakly separated** and its pooled choice agrees with at most 2/3
|
||||
seeds; it is "best among tested candidates", not robust or optimal.
|
||||
- The `S_j` rule is materially exercised (53/162 cells) and conditions all results.
|
||||
|
||||
**Not supported / cannot be concluded.**
|
||||
|
||||
- Statistical superiority or significance (min attainable sign-flip p = 0.25).
|
||||
- That the method has *no* effect (non-significance ≠ equivalence).
|
||||
- A universal or globally optimal beta.
|
||||
- That prototype displacement implies better detection.
|
||||
- Any cross-condition pooling as if the 18 cells were independent replicates.
|
||||
- The paper-comparison deviation magnitudes (source absent).
|
||||
- Any privacy claim from the `N_ij` flow without a threat model.
|
||||
|
||||
---
|
||||
|
||||
## 10. Recommended replacement wording for thesis section A.7 (Indonesian)
|
||||
|
||||
> **Keterbatasan bukti statistik.** Grid eksperimen yang telah diselesaikan terdiri atas enam
|
||||
> kondisi (dua dataset × tiga nilai `α`) dengan tiga seed per kondisi, sehingga setiap perbandingan
|
||||
> berpasangan antara `original_protean` dan metode usulan hanya memiliki tiga selisih. Dengan tiga
|
||||
> selisih tersebut, uji permutasi tanda dua sisi yang eksak sekalipun tidak dapat menghasilkan nilai
|
||||
> p di bawah 0,25; karena itu hasil eksperimen ini dilaporkan secara deskriptif (nilai tengah,
|
||||
> arah perubahan, dan konsistensi antar-seed), bukan sebagai klaim signifikansi. Ketidaksignifikanan
|
||||
> tidak boleh ditafsirkan sebagai bukti bahwa metode tidak berpengaruh, melainkan sebagai
|
||||
> keterbatasan daya uji akibat jumlah seed yang kecil. Perbedaan hasil yang teramati juga kecil dan
|
||||
> bergantung pada kondisi; hanya kondisi X-IIoTID `α`=0,50 yang konsisten membaik pada ketiga seed.
|
||||
> Pemilihan `β` dilakukan sepenuhnya pada data validasi, dengan margin antara kandidat terbaik dan
|
||||
> kedua terbaik yang kecil (0,0024–0,0122), sehingga nilai `β` terpilih dinyatakan sebagai yang
|
||||
> terbaik di antara kandidat yang diuji pada prosedur validasi, bukan sebagai nilai optimal global
|
||||
> maupun pilihan yang kokoh. Selain itu, aturan peserta agregasi `S_j` merupakan asumsi reproduksi
|
||||
> yang secara material berpengaruh pada 53 dari 162 sel kelas-kondisi; seluruh hasil bersifat
|
||||
> kondisional terhadap asumsi tersebut. Generalisasi juga terbatas pada dua dataset, sepuluh
|
||||
> client, satu arsitektur, tiga tingkat `α`, tiga seed, dan lima kandidat `β` diskret.
|
||||
|
||||
*(This is proposed wording for review; no existing thesis document was edited.)*
|
||||
|
||||
---
|
||||
|
||||
## 11. Reproducibility
|
||||
|
||||
```bash
|
||||
# post-hoc audit (read-only; no training; writes posthoc__*.csv only)
|
||||
.venv/bin/python scripts/posthoc_statistical_audit.py
|
||||
```
|
||||
|
||||
The script:
|
||||
1. re-verifies pairing (dataset, alpha, seed, `manifest_content_hash`, recorded beta) for all 18
|
||||
cells and aborts on any mismatch;
|
||||
2. writes `posthoc__paired_global_per_seed.csv`, `posthoc__paired_global_by_condition.csv`,
|
||||
`posthoc__paired_test_results.csv`, `posthoc__selection_stability.csv`,
|
||||
`posthoc__per_class_summary.csv`, `posthoc__per_client_summary.csv`;
|
||||
3. refuses to overwrite any existing artifact.
|
||||
|
||||
Inputs are the committed `deepcmp__*`, `final__*`, `*__multiseed__validation_per_seed.csv`, and
|
||||
`sj_participant_rule_analysis.csv` tables plus per-run `metadata.json`. No network, no training, no
|
||||
partition regeneration.
|
||||
|
||||
---
|
||||
|
||||
## 12. Unresolved data gaps
|
||||
|
||||
1. **`journal/main.tex` / paper Table IV absent** — the paper's reported accuracy/F1 values cannot
|
||||
be verified from the repository; the reproduction-deviation magnitudes remain unconfirmed.
|
||||
2. **No official PROTEAN code** — the `S_j` participant rule and missing-class handling remain a
|
||||
reproduction assumption (material in 53/162 cells).
|
||||
3. **Three seeds only** — inferential power is fundamentally limited; no significant result is
|
||||
attainable and bootstrap/interval estimates would be unreliable.
|
||||
4. **One missing validation artifact set** for `xiiotid__alpha0.5__seed0__original_protean`
|
||||
(documented in the README) — does not affect the six selections but limits that cell's
|
||||
validation-side diagnostics.
|
||||
5. **Metric mismatch** between the per-client validation selection criterion and the global test
|
||||
headline metric cannot be removed post-hoc; it is a design/protocol property.
|
||||
|
||||
---
|
||||
|
||||
## Appendix — Limitations classification (task Phase 5)
|
||||
|
||||
| Item | Classification |
|
||||
|---|---|
|
||||
| A. Limited seeds / statistical evidence | Computable (done: descriptive + exact tests) and a **design-scope limitation** for significance |
|
||||
| B. `S_j` participant rule (53/162) | **Requires source-code/protocol verification** (no official code) → documented reproduction assumption |
|
||||
| C. Baseline reproduction discrepancy | **Requires the external source** (`journal/main.tex` / paper table; absent here); report as reproduction difference, not a defect |
|
||||
| D. Selection margins and seed agreement | **Computable** (done; margins 0.0024–0.0122 verified) |
|
||||
| E. Selection metric vs headline metric | **Computable/traceable in code** (confirmed: validation per-client mean vs global test rare-F1) |
|
||||
| F. Experimental scope (2 datasets, 10 clients, 1 architecture, 3 α, 3 seeds, 5 betas) | **Design-scope limitation** — cannot be removed post-hoc; needs additional experiments |
|
||||
| G. Support information / privacy (`N_ij` at server) | **Requires protocol verification (done: `N_ij` is sent) + threat-model analysis** for any privacy claim; no vulnerability is claimed here |
|
||||
@@ -0,0 +1,233 @@
|
||||
# 1-thread seed-0 re-run: validation selection vs. the 108-run grid
|
||||
|
||||
Status: **exploratory consistency check**, single seed. It does not replace, correct or
|
||||
re-select anything in `FINAL_EXPERIMENTAL_SYNTHESIS.md`. The primary selection of the thesis
|
||||
remains the pooled validation across clients and seeds of the 108-run grid.
|
||||
|
||||
## 1. What was run
|
||||
|
||||
- 30 runs: 2 datasets (X-IIoTID, 5G-NIDD) x 3 alpha (0.25, 0.5, 0.75) x 5 beta
|
||||
(0, 0.25, 0.5, 0.75, 1), `seed = 0`, `support_weighted` mode.
|
||||
- 1 thread per training process, 3 processes in parallel. 2026-10-27T01:13Z to
|
||||
2026-10-28T18:00Z (2026-10-27 08:13 to 2026-10-29 01:00 WIB), about 40.8 h.
|
||||
- All 30 runs ended `completed exit 0` with a `COMPLETE` marker; 0 failed, retry pass was empty.
|
||||
- Outputs live in the git-ignored `results/sweep/` (runs, `summary.csv`, `analysis/`). They are
|
||||
not committed. The orchestration record (including a gate-deadlock fix) is
|
||||
`results/sweep/relaunch_report.md`, also untracked.
|
||||
|
||||
Before the main queue continued, `reference_check.py` compared the first two runs (X-IIoTID
|
||||
alpha 0.25 seed 0, beta 0 and 1) with the audit values; the maximum difference to the manual
|
||||
verdict was 4.3e-10 and every |z| was at most 0.12.
|
||||
|
||||
## 2. Method
|
||||
|
||||
`results/sweep/analyze_sweep.py` (read-only, deterministic; two executions gave byte-identical
|
||||
CSVs):
|
||||
|
||||
1. **Stage 1, validation only.** For each (dataset, alpha) choose the beta with the highest
|
||||
`val_rare_class_macro_f1_per_client_mean`; ties go to the smaller beta. `selection.csv` is
|
||||
written before any test file is opened.
|
||||
2. **Stage 2.** Test rare-class macro-F1 at every beta, read only after stage 1.
|
||||
(`test_at_selected_beta.csv`.) Descriptive; not used to choose anything.
|
||||
3. **Stage 3.** Absolute differences to the earlier grid run of the same
|
||||
(dataset, alpha, seed 0, beta). (`repro_vs_previous.csv`.)
|
||||
|
||||
`results/sweep/compare_with_grid.py` then compares the sweep's choice with the grid's seed-0
|
||||
choice and the grid's pooled choice, using validation metrics only.
|
||||
|
||||
## 3. Results
|
||||
|
||||
### 3.1 Run-to-run difference (30 pairs, same configuration, earlier run vs. 1-thread run)
|
||||
|
||||
| metric | median abs. difference | max abs. difference |
|
||||
|---|---|---|
|
||||
| test rare-class macro-F1 | 0.0022 | 0.0127 (5G-NIDD, alpha 0.5, beta 0.75) |
|
||||
| validation selection metric | 0.0029 | 0.0328 |
|
||||
|
||||
None of the 30 pairs is exactly equal. The cause is not established (section 3.6 tests thread
|
||||
count for one configuration). Because the 1-thread setup turned out to be exactly reproducible
|
||||
(section 3.6), "run-to-run" in sections 3.1 to 3.4 means earlier grid versus 1-thread sweep: a
|
||||
difference between setups, not noise inside one setup.
|
||||
|
||||
### 3.2 Seed-0 selection
|
||||
|
||||
| dataset | alpha | beta (sweep) | beta (grid, seed 0) | beta (grid, pooled) | sweep margin | grid s0 margin |
|
||||
|---|---|---|---|---|---|---|
|
||||
| X-IIoTID | 0.25 | 0.75 | 0.75 | 0 | 0.0413 | 0.0377 |
|
||||
| X-IIoTID | 0.50 | 0.50 | 0.50 | 0.75 | 0.0074 | 0.0078 |
|
||||
| X-IIoTID | 0.75 | 0.50 | 0.50 | 0.50 | 0.0004 | 0.0075 |
|
||||
| 5G-NIDD | 0.25 | 0.25 | 0.25 | 0 | 0.0155 | 0.0109 |
|
||||
| 5G-NIDD | 0.50 | 0.75 | 1.00 | 1.00 | 0.0053 | 0.0044 |
|
||||
| 5G-NIDD | 0.75 | 0.25 | 0.50 | 0.50 | 0.0132 | 0.0021 |
|
||||
|
||||
"Margin" is the validation score of the best beta minus that of the runner-up.
|
||||
|
||||
- The sweep and grid seed-0 choices coincide in **4 of 6** conditions.
|
||||
- The two disagreements are both 5G-NIDD. At alpha 0.5 the sweep's beta is rank 3 in the grid's
|
||||
seed-0 ranking; at alpha 0.75 it is rank 4. These two conditions also show the largest
|
||||
per-beta validation differences between the two runs (0.0328 and 0.0262).
|
||||
- The sweep beta equals the grid **pooled** beta in 1 of 6, but the grid's own seed-0 beta
|
||||
equals its pooled beta in only 3 of 6. A seed-0 versus pooled mismatch is therefore expected
|
||||
and is not a measure of reproducibility.
|
||||
- X-IIoTID alpha 0.75 has a sweep margin of 0.0004, far below the median validation run-to-run
|
||||
difference (0.0029), yet its choice coincides with the grid's. The narrow margin did not
|
||||
produce a different choice here.
|
||||
|
||||
### 3.3 Test rare-class macro-F1 at the validation-selected beta (descriptive, seed 0)
|
||||
|
||||
| dataset | alpha | selected beta | test @ selected | test @ beta 0 |
|
||||
|---|---|---|---|---|
|
||||
| X-IIoTID | 0.25 | 0.75 | 0.6692 | 0.6420 |
|
||||
| X-IIoTID | 0.50 | 0.50 | 0.6439 | 0.6131 |
|
||||
| X-IIoTID | 0.75 | 0.50 | 0.5068 | 0.5263 |
|
||||
| 5G-NIDD | 0.25 | 0.25 | 0.8876 | 0.8612 |
|
||||
| 5G-NIDD | 0.50 | 0.75 | 0.8793 | 0.8694 |
|
||||
| 5G-NIDD | 0.75 | 0.25 | 0.9065 | 0.9024 |
|
||||
|
||||
Selected minus beta 0: +0.0272, +0.0308, -0.0195 (X-IIoTID alpha 0.25 / 0.5 / 0.75) and
|
||||
+0.0264, +0.0099, +0.0042 (5G-NIDD alpha 0.25 / 0.5 / 0.75). In 5 of 6 conditions the test value
|
||||
at the validation-selected beta is above that at beta 0; in X-IIoTID alpha 0.75 it is below.
|
||||
|
||||
Four gaps (absolute value 0.0195 to 0.0308) exceed the largest test run-to-run difference seen
|
||||
in section 3.1 (0.0127). The two 5G-NIDD gaps at alpha 0.5 and 0.75 (0.0099 and 0.0042) lie
|
||||
within the range of that difference (median 0.0022, max 0.0127) and should not be read as
|
||||
improvements. The run-to-run difference compares two runs of one configuration; it is a rough
|
||||
yardstick, not a noise bound for a difference between two betas.
|
||||
|
||||
### 3.4 Noise checks (`results/sweep/check_noise.py` -> `analysis/noise_checks.json`)
|
||||
|
||||
Read-only, no training. The 30 pairs are not independent (the five betas of a condition share
|
||||
one partition), so the sign counts below are descriptive only.
|
||||
|
||||
- **Where the runs first differ.** All 30 pairs already differ at round 0 (max absolute
|
||||
difference in rare-class macro-F1 1.8e-3; 0 of 30 exactly equal). The number of evaluated
|
||||
samples is identical in every round of every pair, so data and partitions are the same. The
|
||||
difference is small at round 0 (median 3.1e-4) and **grows over the rounds** (median 2.1e-3 and
|
||||
max 1.5e-2 at the last round; larger at the last round than at round 0 in 24 of 30 pairs).
|
||||
A tiny first-round difference that is amplified by later rounds fits the pattern; it does not
|
||||
identify what produced the first-round difference.
|
||||
- **Direction.** Test rare-F1, sweep minus grid: 14 higher, 16 lower, mean signed -0.0004 against
|
||||
mean absolute 0.0034. Validation selection metric: 15 higher, 15 lower, mean signed -0.0004
|
||||
against mean absolute 0.0057. The differences scatter around zero; there is no sign of a
|
||||
systematic offset. (A two-sided sign test gives p = 0.86 and 1.0, but the pairs are dependent,
|
||||
so this is not a significance claim.)
|
||||
- **By dataset.** Mean absolute validation difference: X-IIoTID 0.0031, 5G-NIDD 0.0082 (about
|
||||
2.7 times larger). Test: 0.0026 vs 0.0042 (about 1.6 times). 5G-NIDD is the noisier dataset
|
||||
in this comparison, consistent with both disagreements sitting there.
|
||||
- **Ranking stability** (Spearman over the five betas, sweep vs grid, validation): X-IIoTID
|
||||
1.00 / 0.90 / 1.00 and 5G-NIDD 0.90 / 0.50 / 0.30 for alpha 0.25 / 0.5 / 0.75. Betas whose
|
||||
sweep validation score lies within the condition's own maximum run-to-run difference of the
|
||||
best beta (a crude yardstick): X-IIoTID alpha 0.25 {0.75}; alpha 0.5 {0.5, 0.75}; alpha 0.75
|
||||
{0, 0.25, 0.5}; 5G-NIDD alpha 0.25 {0.25}; alpha 0.5 {0, 0.75, 1}; alpha 0.75 {0, 0.25, 0.5}.
|
||||
Selections with one beta in that set (X-IIoTID alpha 0.25, 5G-NIDD alpha 0.25) are the least
|
||||
ambiguous; the others cannot separate their top candidates from the noise.
|
||||
- **Third reference point** (X-IIoTID alpha 0.25 seed 0, test rare-F1; from the earlier
|
||||
5-thread smoke run recorded in `reference_check.json`): beta 0: smoke 0.6402, grid 0.6414,
|
||||
sweep 0.6420; beta 1: smoke 0.5721, grid 0.5841, sweep 0.5931. For beta 1 the three setups
|
||||
span 0.021, larger than the sweep-vs-grid difference alone (0.0089).
|
||||
|
||||
### 3.5 What the thread hypothesis rests on
|
||||
|
||||
- The earlier grid used several cores per process (CPU 741 to 746 % in the X-IIoTID alpha 0.25
|
||||
runtime table, about 7.4 cores); the sweep forces 1 thread (`thread1_launcher.py`,
|
||||
`NLWP = 1` observed). Multi-threaded reductions can change floating-point summation order, so
|
||||
a thread effect is plausible. `BASELINE_VALIDATION.md` (F.2) reports that two invocations of
|
||||
`run_federated` with the same seed gave exactly equal results in a regression test on a small
|
||||
fixture, and that no nondeterminism source was observed at the tested scales on this CPU
|
||||
backend. That says a same-setup repeat was deterministic there; it does not show that full-size
|
||||
runs are bit-reproducible, and it does not test the thread hypothesis.
|
||||
- Confounders that were **not** controlled: the planning document recorded 8 CPU threads and
|
||||
about 29 GiB RAM for the earlier work, whereas this host has `nproc = 12` and 48 GiB; the old
|
||||
run metadata records a different repository path (`.../projects/perdalam-protean`); the
|
||||
metadata stores no PyTorch version, so a library difference cannot be excluded (current:
|
||||
2.14.1+cpu). Whether the grid ran on a different machine is inferred, not verified.
|
||||
|
||||
### 3.6 Repeat and multi-thread test (X-IIoTID alpha 0.25 seed 0 beta 0; `results/sweep_repro/`)
|
||||
|
||||
Two extra runs of one configuration on this host: same partition (hash unchanged), same
|
||||
hyperparameters, same 11 GiB memory scope. A: 1 thread through `thread1_launcher.py`, identical
|
||||
to the sweep command (CPU 99 %, wall 9 704 s). B: 8 threads through `run_baseline.py` directly
|
||||
(CPU 758 %, wall 4 546 s). Script: `results/sweep_repro/compare_repro.py`.
|
||||
|
||||
| pair | test rare-F1 abs diff | val selection metric abs diff | last-round rare-F1 diff | all result JSON equal | prototype snapshot byte-identical |
|
||||
|---|---|---|---|---|---|
|
||||
| A (1 thread repeat) vs sweep | 0 | 0 | 0 | yes | yes |
|
||||
| A (= sweep) vs grid | 6.2e-4 | 1.27e-3 | 3.4e-4 | no | no |
|
||||
| B (8 threads) vs A (= sweep) | 1.86e-3 | 4.6e-4 | 1.9e-3 | no | no |
|
||||
| B (8 threads) vs grid | 2.47e-3 | 8.0e-4 | 2.2e-3 | no | no |
|
||||
|
||||
- **The 1-thread setup is exactly reproducible** (one configuration, one repeat): every compared
|
||||
result file and the prototype snapshot of A equal the sweep run. The sweep therefore contains no
|
||||
random run-to-run noise; the grid-vs-sweep differences are deterministic consequences of the
|
||||
setup, not luck of a single run.
|
||||
- **Thread count changes the result.** B differs from A by 1.86e-3 on test rare-F1, the same order
|
||||
as the median grid-vs-sweep difference (2.2e-3). One pair only.
|
||||
- **Thread count alone does not reproduce the grid.** B is not identical to the grid either. On
|
||||
test rare-F1 it is farther from the grid (2.47e-3) than the 1-thread run is (6.2e-4); on the
|
||||
validation metric it is slightly closer (8.0e-4 vs 1.27e-3). Host, PyTorch version and the grid's
|
||||
exact thread count (CPU 741 to 746 % suggests about 7 to 8, not verified) remain uncontrolled.
|
||||
- **Not tested:** whether the 8-thread setup reproduces itself (needs an 8-thread repeat); any
|
||||
other configuration, in particular 5G-NIDD, where the two beta disagreements occur. This
|
||||
configuration's grid-vs-sweep difference (6.2e-4) is below the median over all 30 pairs, so it
|
||||
is a favourable case for agreement and says little about the 5G-NIDD cases.
|
||||
|
||||
### 3.7 Repeat and multi-thread test, 5G-NIDD alpha 0.5 beta 0.75 (the largest disagreement)
|
||||
|
||||
Same protocol as section 3.6, on the configuration where the grid and the sweep disagreed most
|
||||
about which beta to choose. Partition hash unchanged. A: 1 thread, CPU 99 %, wall 16 752 s.
|
||||
B: 8 threads, CPU 762 %, wall 9 722 s. Outputs in `results/sweep_repro/5gnidd_a0.5_b0.75/`.
|
||||
|
||||
| run | test rare-F1 | test macro-F1 | test accuracy | validation selection metric |
|
||||
|---|---|---|---|---|
|
||||
| sweep (1 thread) | 0.879315 | 0.853592 | 0.745404 | 0.771921 |
|
||||
| A, 1-thread repeat | 0.879315 | 0.853592 | 0.745404 | 0.771921 |
|
||||
| B, 8 threads | 0.875942 | 0.853482 | 0.746436 | 0.744348 |
|
||||
| grid (earlier) | 0.866627 | 0.848043 | 0.746765 | 0.750661 |
|
||||
|
||||
| pair | test rare-F1 abs diff | validation metric abs diff | result JSON equal | snapshot identical |
|
||||
|---|---|---|---|---|
|
||||
| A vs sweep | 0 | 0 | 4/4 | yes |
|
||||
| A vs grid | 1.27e-2 | 2.13e-2 | 0/4 | no |
|
||||
| B vs sweep | 3.37e-3 | 2.76e-2 | 0/4 | no |
|
||||
| B vs grid | 9.32e-3 | 6.31e-3 | 0/4 | no |
|
||||
|
||||
- **The 1-thread setup is exactly reproducible on this dataset too.** Every compared result file
|
||||
and the prototype snapshot of A equal the sweep run. Together with section 3.6 this holds for
|
||||
the two configurations tested (one X-IIoTID, one 5G-NIDD).
|
||||
- **Eight threads do not reproduce the grid here either.** B sits between the sweep and the grid,
|
||||
and which one it is closer to depends on the metric: on test rare-F1 it is closer to the sweep
|
||||
(3.4e-3 vs 9.3e-3), on the validation metric it is closer to the grid (6.3e-3 vs 2.8e-2). No
|
||||
single conclusion follows from this metric split.
|
||||
- **Thread count changes this configuration more than X-IIoTID**: B differs from the sweep by
|
||||
3.4e-3 on test rare-F1 here, against 1.9e-3 there.
|
||||
- **Consequence for the beta disagreement.** Since the 1-thread result is deterministic and the
|
||||
grid result is not reproduced by 8 threads, the grid-vs-sweep difference in this condition is a
|
||||
reproducible consequence of a setup difference whose exact ingredient is not identified. It is
|
||||
not run-to-run randomness of the sweep.
|
||||
|
||||
## 4. Interpretation limits
|
||||
|
||||
- One seed. The grid pools three. Nothing here is a significance test.
|
||||
- Where the sweep and the grid disagree (5G-NIDD alpha 0.5 and 0.75), a different beta is the
|
||||
best of the tested candidates under a slightly different realization of training; this does
|
||||
not show that either beta is better.
|
||||
- Thread count as the cause of the grid-vs-sweep difference is partly supported but not
|
||||
established (sections 3.6 and 3.7): threading changes the result, yet 8 threads on this host
|
||||
does not reproduce the grid, on either of the two configurations tested (X-IIoTID alpha 0.25
|
||||
beta 0; 5G-NIDD alpha 0.5 beta 0.75). Hardware, PyTorch version and the grid's exact thread
|
||||
count stay uncontrolled.
|
||||
- The 1-thread determinism result rests on one repeat per configuration (two configurations). The
|
||||
8-thread setup has not been repeated, so its own reproducibility is unknown.
|
||||
- No claim is made that support weighting improves detection, and the selected beta is "best
|
||||
among the tested candidates under the defined validation procedure", not a global optimum.
|
||||
- `S_j` handling remains the documented reproduction assumption.
|
||||
|
||||
## 5. Reproduce
|
||||
|
||||
```bash
|
||||
.venv/bin/python results/sweep/analyze_sweep.py
|
||||
.venv/bin/python results/sweep/compare_with_grid.py
|
||||
```
|
||||
|
||||
Both only read; they write into `results/sweep/analysis/`. The scripts and CSVs are untracked
|
||||
because `results/` is git-ignored.
|
||||
@@ -0,0 +1,11 @@
|
||||
# Transient driver runtime files (not part of the research record).
|
||||
driver.lock
|
||||
summary.lock
|
||||
HEARTBEAT
|
||||
|
||||
# Per-run result trees are regenerable/ignored by the repository-level
|
||||
# `results/` rule; the analysis tables and REPORT_DATA.md are tracked instead.
|
||||
|
||||
# Smoke-run prototype snapshots are bulky and not part of the scientific record.
|
||||
smoke/analysis/*__prototype_snapshot.json
|
||||
smoke/processed/
|
||||
@@ -0,0 +1,52 @@
|
||||
2026-10-30T04:26:48Z /home/willtanoe/project/prototype-agregation/results/xiiotid__alpha0.25__seed0__original_protean/val_global_metrics.json
|
||||
2026-10-30T04:26:48Z /home/willtanoe/project/prototype-agregation/results/xiiotid__alpha0.25__seed0__original_protean/val_selection.json
|
||||
# ranking.py run at 2026-10-31T05:03:55Z
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__original_protean/results/xiiotid__alpha0.25__seed0__original_protean/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__original_protean/results/xiiotid__alpha0.25__seed0__original_protean/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/xiiotid__alpha0.25__seed0__support_weighted__beta0/results/xiiotid__alpha0.25__seed0__support_weighted__beta0/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/xiiotid__alpha0.25__seed0__support_weighted__beta0/results/xiiotid__alpha0.25__seed0__support_weighted__beta0/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/xiiotid__alpha0.25__seed0__support_weighted__beta0.25/results/xiiotid__alpha0.25__seed0__support_weighted__beta0.25/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/xiiotid__alpha0.25__seed0__support_weighted__beta0.25/results/xiiotid__alpha0.25__seed0__support_weighted__beta0.25/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/xiiotid__alpha0.25__seed0__support_weighted__beta0.5/results/xiiotid__alpha0.25__seed0__support_weighted__beta0.5/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/xiiotid__alpha0.25__seed0__support_weighted__beta0.5/results/xiiotid__alpha0.25__seed0__support_weighted__beta0.5/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/xiiotid__alpha0.25__seed0__support_weighted__beta0.75/results/xiiotid__alpha0.25__seed0__support_weighted__beta0.75/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/xiiotid__alpha0.25__seed0__support_weighted__beta0.75/results/xiiotid__alpha0.25__seed0__support_weighted__beta0.75/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/xiiotid__alpha0.25__seed0__support_weighted__beta1/results/xiiotid__alpha0.25__seed0__support_weighted__beta1/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/xiiotid__alpha0.25__seed0__support_weighted__beta1/results/xiiotid__alpha0.25__seed0__support_weighted__beta1/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__original_protean/results/5gnidd__alpha0.5__seed0__original_protean/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__original_protean/results/5gnidd__alpha0.5__seed0__original_protean/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/5gnidd__alpha0.5__seed0__support_weighted__beta0/results/5gnidd__alpha0.5__seed0__support_weighted__beta0/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/5gnidd__alpha0.5__seed0__support_weighted__beta0/results/5gnidd__alpha0.5__seed0__support_weighted__beta0/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/5gnidd__alpha0.5__seed0__support_weighted__beta0.25/results/5gnidd__alpha0.5__seed0__support_weighted__beta0.25/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/5gnidd__alpha0.5__seed0__support_weighted__beta0.25/results/5gnidd__alpha0.5__seed0__support_weighted__beta0.25/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/5gnidd__alpha0.5__seed0__support_weighted__beta0.5/results/5gnidd__alpha0.5__seed0__support_weighted__beta0.5/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/5gnidd__alpha0.5__seed0__support_weighted__beta0.5/results/5gnidd__alpha0.5__seed0__support_weighted__beta0.5/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/5gnidd__alpha0.5__seed0__support_weighted__beta0.75/results/5gnidd__alpha0.5__seed0__support_weighted__beta0.75/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/5gnidd__alpha0.5__seed0__support_weighted__beta0.75/results/5gnidd__alpha0.5__seed0__support_weighted__beta0.75/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/5gnidd__alpha0.5__seed0__support_weighted__beta1/results/5gnidd__alpha0.5__seed0__support_weighted__beta1/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/results/sweep/runs/5gnidd__alpha0.5__seed0__support_weighted__beta1/results/5gnidd__alpha0.5__seed0__support_weighted__beta1/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/queue_screen.csv
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_beta__b1.5/results/xiiotid__alpha0.25__seed0__v_beta__b1.5/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_beta__b1.5/results/xiiotid__alpha0.25__seed0__v_beta__b1.5/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5/results/xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5/results/xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_cap__b1__c4/results/xiiotid__alpha0.25__seed0__v_cap__b1__c4/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_cap__b1__c4/results/xiiotid__alpha0.25__seed0__v_cap__b1__c4/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_cap__b1__c2/results/xiiotid__alpha0.25__seed0__v_cap__b1__c2/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_cap__b1__c2/results/xiiotid__alpha0.25__seed0__v_cap__b1__c2/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_minsup__t10/results/xiiotid__alpha0.25__seed0__v_minsup__t10/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_minsup__t10/results/xiiotid__alpha0.25__seed0__v_minsup__t10/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_logweight/results/xiiotid__alpha0.25__seed0__v_logweight/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_logweight/results/xiiotid__alpha0.25__seed0__v_logweight/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_beta__b1.5/results/5gnidd__alpha0.5__seed0__v_beta__b1.5/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_beta__b1.5/results/5gnidd__alpha0.5__seed0__v_beta__b1.5/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5/results/5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5/results/5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_cap__b1__c4/results/5gnidd__alpha0.5__seed0__v_cap__b1__c4/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_cap__b1__c4/results/5gnidd__alpha0.5__seed0__v_cap__b1__c4/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_cap__b1__c2/results/5gnidd__alpha0.5__seed0__v_cap__b1__c2/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_cap__b1__c2/results/5gnidd__alpha0.5__seed0__v_cap__b1__c2/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_minsup__t10/results/5gnidd__alpha0.5__seed0__v_minsup__t10/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_minsup__t10/results/5gnidd__alpha0.5__seed0__v_minsup__t10/val_selection.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_logweight/results/5gnidd__alpha0.5__seed0__v_logweight/val_global_metrics.json
|
||||
2026-10-31T05:03:55Z /home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_logweight/results/5gnidd__alpha0.5__seed0__v_logweight/val_selection.json
|
||||
@@ -0,0 +1 @@
|
||||
2026-10-30T04:11:55Z
|
||||
@@ -0,0 +1,167 @@
|
||||
# Phase 3 — candidate modifications
|
||||
|
||||
All candidates below are implemented **only inside `exploration_v2/`**
|
||||
(`exploration_v2/scripts/variants.py`, `run_variant.py`, unit tests in
|
||||
`exploration_v2/tests/`). No file under `src/`, `configs/`, `tests/`,
|
||||
`scripts/`, `results/`, `artifacts/` or `planningawal/` was changed.
|
||||
|
||||
Evidence codes used below are the Phase 2 measurements in
|
||||
`exploration_v2/results/phase2_*.csv` (restored 108-run grid, read only).
|
||||
|
||||
Baseline facts used by every candidate (measured, pooled over seeds 0–2):
|
||||
|
||||
| condition | max weight share at β=1 | classes with `|S_j|<M` | mean support CV | largest β step loss (validation) |
|
||||
|---|---|---|---|---|
|
||||
| X-IIoTID α=0.25 | 0.528 | 6.3 / 9 | 1.442 | 0.75→1.00: −0.047 |
|
||||
| 5G-NIDD α=0.25 | 0.454 | 5.3 / 9 | 1.302 | 0.25→0.50: −0.024 |
|
||||
| X-IIoTID α=0.50 | 0.400 | 2.3 / 9 | 1.183 | 0.75→1.00: −0.006 |
|
||||
| 5G-NIDD α=0.50 | 0.414 | 1.3 / 9 | 1.225 | 0.00→0.25: −0.042 |
|
||||
| X-IIoTID α=0.75 | 0.284 | 1.0 / 9 | 0.881 | 0.50→0.75: −0.004 |
|
||||
| 5G-NIDD α=0.75 | 0.298 | 1.3 / 9 | 0.916 | 0.50→0.75: −0.018 |
|
||||
|
||||
The two failure modes the candidates target are therefore:
|
||||
(a) at high heterogeneity the β=1 weight vector places >50 % of a class's
|
||||
weight on one client and the rare-class metric falls; (b) the deployed
|
||||
per-client-mean selection metric disagrees with the global headline metric
|
||||
(Phase 2: X-IIoTID α=0.25 and 5G-NIDD α=0.50).
|
||||
|
||||
---
|
||||
|
||||
## C1. Extended beta grid (β = 1.5) — `v_beta` β=1.5
|
||||
|
||||
- **Mechanism.** Keep `w_i ∝ N_ij^β` but allow β > 1. Concentrates weight more
|
||||
strongly than the frozen grid's endpoint.
|
||||
- **Motivating evidence.** 5G-NIDD α=0.50 selected the boundary value β=1.00 and
|
||||
its validation curve was still rising at the boundary (0.6872 → 0.6924),
|
||||
so the frozen grid cannot tell whether the optimum lies beyond 1. Also tests
|
||||
whether the X-IIoTID α=0.25 degradation is monotone in β.
|
||||
- **Definition change.** Same operator, extended candidate range; not a new
|
||||
method. Selection procedure unchanged apart from the extra candidate.
|
||||
- **Cost.** One full run per condition, same as a normal beta run.
|
||||
- **Failure modes.** At α=0.25 it should worsen concentration and rare-class
|
||||
recall further; at 5G-NIDD α=0.50 the boundary gain may be seed noise.
|
||||
|
||||
## C2. Shrinkage toward equal weighting — `v_shrink` β=1, λ=0.5
|
||||
|
||||
- **Mechanism.** `p_i = N_ij^β / Σ N_ij^β`; `w_i = (1−λ)/|S_j| + λ·p_i`.
|
||||
λ=0 is the equal mean, λ=1 is the current method. λ=0.5 is fixed a priori.
|
||||
- **Motivating evidence.** The largest losses occur where β=1 concentration is
|
||||
highest (X-IIoTID α=0.25: max share 0.528; 5G-NIDD α=0.25: 0.454). Halving
|
||||
the displacement should retain some support signal while bounding the tail.
|
||||
- **Definition change.** New aggregation operator; would need its own name
|
||||
(“λ-shrunk support-weighted aggregation”) if adopted.
|
||||
- **Cost.** One run per condition. λ=0.5 is not tuned on screening data; if it
|
||||
ranks top-2 it goes to confirmation unchanged.
|
||||
- **Failure modes.** λ=0.5 may be too weak to prevent the α=0.25 loss, or too
|
||||
strong to keep the 5G-NIDD α=0.75 gain; a single λ is unlikely to be right
|
||||
everywhere.
|
||||
|
||||
## C3. Weight capping at 4× median — `v_cap` β=1, c=4
|
||||
|
||||
- **Mechanism.** `w_i ∝ min(N_ij^β, c · median_k(N_kj^β))`, then normalise.
|
||||
Caps the influence of a single high-support client without discarding it.
|
||||
- **Motivating evidence.** In the worst cells the top client holds ~0.45–0.53
|
||||
of a class's weight; 53/162 class-cells have `|S_j|<M`, where that
|
||||
concentration is largest (mean max share 0.463 vs 0.364 for full `S_j`).
|
||||
- **Definition change.** New operator (“capped support-weighted aggregation”).
|
||||
- **Cost.** One run per condition; `c` fixed at 4.
|
||||
- **Failure modes.** Cap may bind on legitimate high-support classes and
|
||||
reduce the benefit seen at 5G-NIDD α=0.75; median is unstable when `|S_j|`
|
||||
is 2–3.
|
||||
|
||||
## C4. Weight capping at 2× median — `v_cap` β=1, c=2 (likely negative)
|
||||
|
||||
- **Mechanism.** Same as C3 with a much tighter cap.
|
||||
- **Motivating evidence.** Deliberate stress test of the capping mechanism;
|
||||
it should approach equal weighting in cells with `|S_j|` = 2–3.
|
||||
- **Definition change.** Same operator family as C3.
|
||||
- **Cost.** One run per condition.
|
||||
- **Failure modes.** Expected to erase most support signal and behave like
|
||||
β=0; included to show whether C3's effect is monotone in the cap. This is a
|
||||
candidate we expect **not** to help.
|
||||
|
||||
## C5. Minimum-support threshold — `v_minsup` t=10, equal weights
|
||||
|
||||
- **Mechanism.** Drop contributors with `N_ij < 10` from `S_j`, then equal-mean
|
||||
the remaining prototypes. This is a **participant-rule change**, not a
|
||||
weighting change.
|
||||
- **Motivating evidence.** Phase 2 reports that at α=0.25 many classes have
|
||||
`|S_j|<M`; the intuition is that tiny-support prototypes are noisy.
|
||||
- **Definition change.** New method (“minimum-support-filtered equal
|
||||
aggregation”); it also changes the meaning of `S_j`, so it must not be
|
||||
described as the same method with a different weight.
|
||||
- **Cost.** One run per condition.
|
||||
- **Failure modes.** The project's own rule is that `N_ij` is support, not
|
||||
quality; low-support clients may carry the only examples of a rare attack.
|
||||
Dropping them is expected to **hurt** rare-class recall and is included as a
|
||||
negative candidate. It also leaves classes with no contributor if the
|
||||
threshold is too high (documented fallback: keep all).
|
||||
|
||||
## C6. Logarithmic weight function — `v_logweight` w ∝ log(1+N)
|
||||
|
||||
- **Mechanism.** Replace the power law with a concave function of support.
|
||||
Unlike `N^β`, the ratio between a support-1 and a support-1000 client is
|
||||
bounded by log(2)/log(1001) ≈ 0.10 instead of 1/1000.
|
||||
- **Motivating evidence.** The β grid compresses support differences only
|
||||
gradually; a log weight is a stronger, differently-shaped compression that
|
||||
cannot be reached by any β ∈ [0,1]. It tests whether the losses are caused
|
||||
by the *shape* of the power law rather than by concentration alone.
|
||||
- **Definition change.** New weight function (“log-support-weighted
|
||||
aggregation”).
|
||||
- **Cost.** One run per condition.
|
||||
- **Failure modes.** It nearly equalises clients with support above ~100 and
|
||||
may lose the gains at 5G-NIDD α=0.75; the `1+N` offset is arbitrary.
|
||||
|
||||
## C7. Different selection metric (analysis-level, zero runs)
|
||||
|
||||
- **Mechanism.** Keep the current aggregation but select β with validation
|
||||
**global** rare-class macro-F1 (`val_rare_class_macro_f1_global`) instead of
|
||||
the deployed per-client mean (`val_rare_class_macro_f1_per_client_mean`).
|
||||
- **Motivating evidence (measured).** In X-IIoTID α=0.25 the deployed metric
|
||||
ranks β=0 first but the global validation metric ranks β=0.50 first; in
|
||||
5G-NIDD α=0.50 the deployed metric ranks β=1.00 first while the global
|
||||
metric ranks β=0.00 first. The global metric's ranking matches the test
|
||||
ranking in 6/6 conditions; the per-client metric in 4/6. This is a
|
||||
descriptive comparison on existing data, not a significance test.
|
||||
- **Definition change.** No aggregation change; it changes the **selection
|
||||
procedure**, so it should be reported as a procedure result, not as a new
|
||||
aggregation method.
|
||||
- **Cost.** Zero training runs; it re-ranks existing validation files.
|
||||
- **Failure modes.** Using a different metric after seeing test outcomes is
|
||||
exactly the kind of post-hoc choice the protocol forbids. In this
|
||||
exploration it is pre-registered *before* any new run and justified by
|
||||
metric-definition alignment (global validation vs global headline), not by
|
||||
test performance. It still cannot be confirmed on the old seeds.
|
||||
|
||||
## C8. Finer beta grid (analysis-level, zero runs on existing seeds)
|
||||
|
||||
- **Mechanism.** Evaluate the current operator at β = 0.125, 0.375, 0.625,
|
||||
0.875 (or interpolate) to see whether the coarse 0.25 spacing hides a
|
||||
better point.
|
||||
- **Motivating evidence.** The largest adjacent-step changes are 0.047
|
||||
(X-IIoTID α=0.25, 0.75→1.00) and 0.065 test (5G-NIDD α=0.25, 0.25→0.50), so
|
||||
the response is not flat between grid points in the worst cells.
|
||||
- **Definition change.** Same operator; finer candidate set.
|
||||
- **Cost.** New runs would be required for real evidence; **not** run in this
|
||||
exploration because β is a one-dimensional grid and the budget is reserved
|
||||
for mechanism candidates. Only the already-observed coarse grid is reported.
|
||||
- **Failure modes.** Any apparent interior optimum could be seed noise; the
|
||||
existing three-seed spread is already as large as the between-β spread.
|
||||
|
||||
---
|
||||
|
||||
## Candidates deliberately not implemented
|
||||
|
||||
- Client rejection / Byzantine defence, prototype clustering, cosine distance,
|
||||
personalised FL, attention or quality scoring: out of the thesis scope
|
||||
(`AGENTS.md` §8) and not motivated by the Phase 2 evidence.
|
||||
- Per-class β or per-client β: would multiply the run count and change the
|
||||
method substantially; not screened.
|
||||
|
||||
## Cost and ranking summary
|
||||
|
||||
Six run-based candidates (C1–C6) are screened on two conditions (12 runs).
|
||||
The selection-metric candidate C7 and the finer-grid candidate C8 are
|
||||
analysis-level and cost no training runs. The top two run-based candidates go
|
||||
to confirmation on two new seeds (20 runs including three reference configs).
|
||||
Total planned: **32 new training runs**.
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"status": "complete",
|
||||
"utc": "2026-11-01T22:35:36Z",
|
||||
"runs_done": 20,
|
||||
"runs_failed": 0
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
# exploration_v2 — final handoff
|
||||
|
||||
Updated: 2026-11-02T03:36Z. Status: **complete**.
|
||||
|
||||
## Result in one line
|
||||
|
||||
The campaign finished on 2026-11-01T22:35:36Z: **34/34 scientific runs done, 0
|
||||
terminal failures, 66.4 h of the 96 h budget**. The pre-registered top-2
|
||||
screening candidates were `v_shrink` (β=1, λ=0.5) and `v_cap4` (β=1, cap
|
||||
4×median). On the four confirmatory pairs (2 conditions × seeds 3 and 4),
|
||||
`v_shrink` improved over the **original baseline** on validation in 4/4 pairs
|
||||
(mean +0.0180, sd 0.0141; test +0.0184, 4/4). `v_cap4` did **not** improve
|
||||
(+0.0047, 2/4). Neither variant dominated the current method's per-pair best of
|
||||
{original, β=0.5, β=1}: `v_shrink` mean −0.0153 on validation.
|
||||
|
||||
## Frozen artefacts
|
||||
|
||||
| item | value |
|
||||
|---|---|
|
||||
| `PLAN.sha256` | `2118f31b…c978e` at 2026-10-30T04:07:47Z |
|
||||
| `ranking.sha256` | `f43ebc76…b054d3` at 2026-10-31T05:03:55Z |
|
||||
| `DONE` | `status=complete`, 20 confirmation done, 0 failed, 2026-11-01T22:35:36Z |
|
||||
| `REPORT.md` | final narrative + auto tables |
|
||||
| `REPORT_DATA.md` | all tables |
|
||||
| `analysis/*.csv` | per-run, per-seed, summary, wall time |
|
||||
|
||||
## What a later session should do
|
||||
|
||||
1. Read `REPORT.md` §5.8 and §8. The narrative is complete; no re-analysis is
|
||||
required.
|
||||
2. Optional follow-ups (new work, not corrections): test `v_shrink` at α=0.75
|
||||
and on other datasets; test a pooled-across-seeds selection; test the C7
|
||||
selection-metric change on new seeds. These are hypotheses, not promises.
|
||||
3. Do not re-rank. `ranking.sha256` is frozen and `REPORT.md` records the
|
||||
pre-registered decision.
|
||||
4. Do not edit any tracked file. `exploration_v2/` is the only new tree;
|
||||
`planningawal/`, `results/`, `artifacts/partitions/`, `src/`, `configs/`,
|
||||
`tests/`, `scripts/` were not modified.
|
||||
|
||||
## Operational notes
|
||||
|
||||
- Three seed-4 reference runs were OOM-killed at the old 11 GiB cap; recovery
|
||||
raised the X-IIoTID cap to 13 GiB, set `max_procs=2`, added a host
|
||||
`MemAvailable ≥ 12 GiB` launch guard, and fixed a retry unit-name collision.
|
||||
Full timeline: `PLAN_AMENDMENTS.md` A1–A5 and `ISSUES.md`.
|
||||
- All failed attempts are archived under `results/attempts/`; the pre-campaign
|
||||
path-bug attempts under `results/_driver_bug_20261030T0410Z/`.
|
||||
- No test metric was read before the ranking freeze; `ACCESS_LOG.txt` contains
|
||||
only validation paths.
|
||||
- The host is shared; the results are conditional on the 13 GiB X-IIoTID cap
|
||||
and on the two conditions/seeds tested.
|
||||
|
||||
## Ready-to-paste prompt for a later session
|
||||
|
||||
```
|
||||
Continue exploration_v2 in ~/project/prototype-agregation. Read
|
||||
exploration_v2/REPORT.md, REPORT_DATA.md, PLAN.md, PLAN_AMENDMENTS.md,
|
||||
ISSUES.md and analysis/*.csv. The campaign is complete (DONE status=complete,
|
||||
34/34 runs, 66.4 h); do not re-rank or re-select. For new work, treat v_shrink
|
||||
(β=1, λ=0.5) as the only candidate that met the pre-registered improvement rule
|
||||
over the original baseline (4/4 pairs, mean +0.0180 val), and remember it did
|
||||
not beat the current method's per-pair best (mean −0.0153). Do not edit tracked
|
||||
files and do not claim significance or generalisation.
|
||||
```
|
||||
@@ -0,0 +1,206 @@
|
||||
# exploration_v2 — issues and deviations log
|
||||
|
||||
This file records anything that could not be completed, permission problems,
|
||||
deviations from PLAN.md, and driver-level failures. Entries are appended by the
|
||||
agent and by the driver.
|
||||
|
||||
## 2026-10-30 — initial state
|
||||
|
||||
- All work is confined to `exploration_v2/`. No tracked file, no file under
|
||||
`src/`, `configs/`, `tests/`, `scripts/`, `results/`, `artifacts/partitions/`
|
||||
or `planningawal/` was modified.
|
||||
- A non-scientific engineering smoke run (3000 rows, 2 rounds, 4 clients,
|
||||
X-IIoTID α=0.25 seed 0) was executed before the PLAN hash was recorded to
|
||||
validate the copied runner. It is not a screening or confirmatory run and its
|
||||
numbers are not used for any ranking.
|
||||
- The restored results contain seeds 0, 1 and 2 only (`seed34_count=0`), so
|
||||
seeds 3 and 4 are genuinely new for confirmation.
|
||||
|
||||
## 2026-10-30T04:09:36Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed0__v_beta__b1.5` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-30T04:09:36Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-30T04:09:36Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed0__v_cap__b1__c4` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-30T04:09:47Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed0__v_beta__b1.5` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-30T04:09:47Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-30T04:09:47Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed0__v_cap__b1__c4` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-30T04:09:47Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed0__v_beta__b1.5` failed after 2 attempt(s); marked terminal failed.
|
||||
|
||||
## 2026-10-30T04:09:47Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5` failed after 2 attempt(s); marked terminal failed.
|
||||
|
||||
## 2026-10-30T04:09:47Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed0__v_cap__b1__c4` failed after 2 attempt(s); marked terminal failed.
|
||||
|
||||
## 2026-10-30T04:09:57Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed0__v_cap__b1__c2` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-30T04:09:57Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed0__v_minsup__t10` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-30T04:09:57Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed0__v_logweight` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-30T04:10Z — driver path bug before any scientific run
|
||||
|
||||
The first driver launch failed all queued wrappers with exit 127 because
|
||||
`run_one_v2.sh` and `run_one_inner_v2.sh` resolved the repository root as
|
||||
`$HERE/../..` while `$HERE` is already `exploration_v2/`. The wrapper therefore
|
||||
looked for `/home/willtanoe/project/.venv/bin/python`. **No training started**:
|
||||
all six attempt directories contain only empty result/log trees and a
|
||||
`.failed` marker with exit 127. They were moved to
|
||||
`exploration_v2/results/_driver_bug_20261030T0410Z/` and are listed in the final
|
||||
run inventory as non-scientific driver failures.
|
||||
|
||||
Fix applied after the PLAN hash: `REPO_ROOT="$HERE/.."` in both scripts. This is
|
||||
an engineering fix, not a methodological change; no screening or confirmatory
|
||||
result existed when it was applied.
|
||||
|
||||
## 2026-10-30T04:10Z — PLAN amendment A1
|
||||
|
||||
Reason: the driver wrapper path bug above. What had been seen: the smoke test
|
||||
(PASS, non-scientific) and six exit-127 wrapper failures with empty run
|
||||
directories. No metric file of any variant existed. The plan's variants,
|
||||
conditions, seeds, ranking metric, budget and stop rules are unchanged.
|
||||
|
||||
## 2026-10-30T04:28Z — ranking/analysis pre-run bug fixes
|
||||
|
||||
While the first screening runs were training (no result file existed yet), a
|
||||
synthetic fixture under `/tmp/opencode/ranktest` exposed two path bugs that
|
||||
would have failed the post-screening ranking: `val_files()` double-counted the
|
||||
`results/` component for both restored and new runs. The helper now takes the
|
||||
run's base directory explicitly. A second fixture
|
||||
(`/tmp/opencode/analyzetest`) exposed a missing `OUT.mkdir` in the analysis
|
||||
script, now added. Neither bug touched any run output, no metric was read, and
|
||||
the PLAN is unchanged. Recorded here because the fixes happened after the plan
|
||||
hash.
|
||||
|
||||
## 2026-10-30T04:32Z — PLAN amendment A2 (in-environment baseline references)
|
||||
|
||||
Added two `original_protean` screening runs at the front of the queue because
|
||||
the restored grid was produced in a different environment and the project's own
|
||||
audit measured non-trivial host/version differences (median 0.0022, max 0.0127
|
||||
test rare-F1). No screening result had been read. Full reason in
|
||||
`PLAN_AMENDMENTS.md` A2. Screening queue is now 14 runs; total planned 34.
|
||||
|
||||
## 2026-10-31T08:20:46Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed4__original_protean` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-31T08:20:56Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed4__original_protean` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-31T08:20:57Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed4__original_protean` failed after 2 attempt(s); marked terminal failed.
|
||||
|
||||
## 2026-10-31T08:26:42Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed4__support_weighted__beta0.5` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-31T08:26:53Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed4__support_weighted__beta0.5` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-31T08:26:54Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed4__support_weighted__beta0.5` failed after 2 attempt(s); marked terminal failed.
|
||||
|
||||
## 2026-10-31T08:27:04Z — driver
|
||||
|
||||
stopping launches: failure rate 2/5 exceeds 20%
|
||||
|
||||
## 2026-10-31T08:35Z — confirmation OOM kills and recovery (amendment A3)
|
||||
|
||||
Two seed-4 confirmation **reference** runs (`original_protean`,
|
||||
`support_weighted__beta0.5`) were OOM-killed inside their 11 GiB systemd scopes
|
||||
(exit surfaced as 143; scope `Result=oom-kill`). Each failed twice; the driver's
|
||||
20 % failure-rate rule stopped new launches at 08:27:04Z while three other runs
|
||||
continued. Failed attempts produced zero-byte logs and no artifacts, so no
|
||||
metric existed. Recovery: attempts archived, runs requeued, `max_procs` 3→2,
|
||||
wrapper now maps scope OOM to 137, and the failure-rate stop yields to the
|
||||
memory-kill throttle. Full rationale: `PLAN_AMENDMENTS.md` A3.
|
||||
|
||||
No confirmatory test metric has been read.
|
||||
|
||||
## 2026-10-31T09:50Z — OOM prevention settings (amendment A4)
|
||||
|
||||
Applied after three seed-4 reference OOM kills: X-IIoTID cap 11→13 GiB,
|
||||
`MAX_PROCS=2`, host `MemAvailable >= 12 GiB` launch guard, OOM→137 mapping and
|
||||
3→2→1 throttle. Two seed-3 confirmation runs were already in flight with the old
|
||||
11 GiB cap; they are left to finish rather than killed. No test metric has been
|
||||
read.
|
||||
|
||||
## 2026-10-31T14:06:20Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed4__original_protean` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-31T14:06:31Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed4__original_protean` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-31T14:06:31Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed4__original_protean` failed after 2 attempt(s); marked terminal failed.
|
||||
|
||||
## 2026-10-31T14:06:41Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed4__support_weighted__beta0.5` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-31T14:06:52Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed4__support_weighted__beta0.5` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-31T14:06:53Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed4__support_weighted__beta0.5` failed after 2 attempt(s); marked terminal failed.
|
||||
|
||||
## 2026-10-31T14:07:03Z — driver
|
||||
|
||||
run `xiiotid__alpha0.25__seed4__support_weighted__beta1` wrapper exit 1; see its logs.
|
||||
|
||||
## 2026-10-31T14:07:03Z — driver
|
||||
|
||||
stopping launches: failure rate 2/6 exceeds 20%
|
||||
|
||||
## 2026-10-31T14:12Z — retry collision fixed (amendment A5)
|
||||
|
||||
The 14:06Z failures were retries blocked by a stale transient scope unit name,
|
||||
not new OOM kills. Evidence: stderr “Failed to start transient scope unit: Unit
|
||||
… was already loaded” and zero-byte `time.txt`; the wrapper then read the old
|
||||
scope's `Result=oom-kill`. Fixed with `reset-failed` before launch and a guard
|
||||
that ignores the old Result when the scope never started. Seed-4 references are
|
||||
running again with the 13 GiB cap. No test metric read.
|
||||
|
||||
## 2026-10-31T14:30Z — A6: in-place wrapper edit caused exit 127 (results unaffected)
|
||||
|
||||
Editing `run_one_v2.sh` while two wrappers were already running corrupted their
|
||||
remaining shell commands (bash reads scripts incrementally); both exited 127
|
||||
after training had finished and were retried. The archived first attempts
|
||||
(`results/attempts/*seed3*v_cap*attempt1`, `*v_shrink*attempt1`) are bit-identical
|
||||
to the final runs for val/test metrics and the round-0 snapshot, so no result
|
||||
changed. Lesson recorded: never edit a bash script while instances are running.
|
||||
@@ -0,0 +1,78 @@
|
||||
# exploration_v2 — key results (one page)
|
||||
|
||||
Status: complete. `DONE` = `status=complete`, 2026-11-01T22:35:36Z.
|
||||
34/34 scientific runs, 0 terminal failures, 66.4 h of 96 h.
|
||||
Plan hash `2118f31b…c978e`; ranking hash `f43ebc76…b054d3` (frozen before any
|
||||
confirmatory run).
|
||||
|
||||
## Question
|
||||
|
||||
Which pre-specified modification to PROTEAN's server-side prototype aggregation
|
||||
improves validation rare-class macro-F1 over (a) the original baseline and
|
||||
(b) the current support-weighted method, and does it hold on seeds never used in
|
||||
the analysis?
|
||||
|
||||
## Screening (validation only; seed 0; 2 conditions)
|
||||
|
||||
Score = mean over X-IIoTID α=0.25 and 5G-NIDD α=0.50 of the paired validation
|
||||
difference in global rare-class macro-F1 vs the in-environment original.
|
||||
|
||||
| rank | variant | score vs baseline | rank by deployed metric |
|
||||
|---|---|---|---|
|
||||
| 1 | `v_shrink` (β=1, λ=0.5) | **+0.0267** | 1 |
|
||||
| 2 | `v_cap4` (β=1, cap 4×median) | **+0.0064** | 2 |
|
||||
| 3 | `v_cap2` (cap 2×median) | −0.0024 | 3 |
|
||||
| 4 | `v_logweight` | −0.0139 | 5 |
|
||||
| 5 | `v_minsup10` | −0.0302 | 6 |
|
||||
| 6 | `v_beta1.5` | −0.0485 | 4 |
|
||||
|
||||
Top-2 margin: 0.0203. Only `v_shrink` was above the current method's best β on
|
||||
validation, by +0.0038.
|
||||
|
||||
## Confirmation (new seeds 3 and 4; 4 pairs)
|
||||
|
||||
| variant | mean Δval vs baseline | sd | positive | mean Δtest | positive | pre-registered improved? |
|
||||
|---|---|---|---|---|---|---|
|
||||
| `v_shrink` | **+0.0180** | 0.0141 | **4/4** | +0.0184 | 4/4 | **yes** |
|
||||
| `v_cap4` | +0.0047 | 0.0263 | 2/4 | +0.0059 | 2/4 | no |
|
||||
|
||||
`v_shrink` per condition (validation, seeds 3/4):
|
||||
X-IIoTID +0.0085 / +0.0329 (mean +0.0207);
|
||||
5G-NIDD +0.0269 / +0.0038 (mean +0.0153).
|
||||
|
||||
## Versus the current method
|
||||
|
||||
Best of {original, β=0.5, β=1} per pair, validation:
|
||||
|
||||
| variant | mean Δ vs current best | sd | pairs better |
|
||||
|---|---|---|---|
|
||||
| `v_shrink` | **−0.0153** | 0.0521 | 2/4 |
|
||||
| `v_cap4` | −0.0286 | 0.0597 | 1/4 |
|
||||
|
||||
The current method's β=1 is very seed-sensitive: mean −0.0163, sd 0.1040,
|
||||
1/4 positive (5G-NIDD seed 3: +0.1158; X-IIoTID seed 4: −0.1384).
|
||||
β=0.5 is more stable: +0.0109, sd 0.0190.
|
||||
|
||||
## Bottom line
|
||||
|
||||
- One modification, **`v_shrink` (half-way between equal and support-weighted)**,
|
||||
met the pre-registered improvement rule over the original baseline on all four
|
||||
confirmation pairs. The gain is modest (~+0.018 rare-class macro-F1) and the
|
||||
test differences agree with validation.
|
||||
- It does **not** beat the current method's per-pair best; it is more stable but
|
||||
lower-peak. No superiority claim is made.
|
||||
- The average hides heterogeneity: on X-IIoTID only 9/20 client-seed pairs
|
||||
improve (mean +0.0295) and the gain is concentrated in C&C/Weaponization/
|
||||
Tampering; on 5G-NIDD 12/20 improve (mean +0.0119). See
|
||||
`analysis/confirm_per_class_variant.csv` and `confirm_per_client_variant.csv`.
|
||||
- The capping candidate (`v_cap4`) did not improve. Extended β=1.5,
|
||||
minimum-support filtering, log-weights and 2× capping were negative in
|
||||
screening.
|
||||
- Four paired observations, no significance test; only two conditions and two
|
||||
new seeds. See `REPORT.md` §6–8 for negative results, deviations and limits.
|
||||
|
||||
## Where the numbers live
|
||||
|
||||
`REPORT.md` (narrative) · `REPORT_DATA.md` (tables) · `analysis/*.csv`
|
||||
(per-run/per-seed) · `ranking.json` + `ranking.sha256` · `ACCESS_LOG.txt`
|
||||
(validation-only ranking reads).
|
||||
@@ -0,0 +1,351 @@
|
||||
# Phase 1 and Phase 2 — inventory and diagnosis (plain language)
|
||||
|
||||
Scope: read-only analysis of the repository, the restored 108-run grid
|
||||
(`results/`), the 30-run 1-thread sweep (`results/sweep/`), the reproducibility
|
||||
runs (`results/sweep_repro/`), and the committed analysis tables
|
||||
(`artifacts/analysis/`). No training was run for this document. Numeric tables
|
||||
are reproduced in `exploration_v2/results/phase2_*.csv`.
|
||||
|
||||
Labels used: **measured** (read or recomputed from an artifact), **inferred**
|
||||
(a reading of measured values), **unknown** (not established by the available
|
||||
files).
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 — what exists
|
||||
|
||||
### 1.1 The research object
|
||||
|
||||
The repository implements PROTEAN (Chennoufi et al., 2025) as a federated
|
||||
intrusion detector. Each of 10 clients trains a small CNN on its local shard,
|
||||
sends model weights and **class prototypes** (the mean embedding of each locally
|
||||
observed class) to a server, and the server builds one **global prototype per
|
||||
class** used for nearest-prototype classification. The thesis modifies exactly
|
||||
one step: how the server combines the clients' class prototypes.
|
||||
|
||||
The implemented operator is:
|
||||
|
||||
```
|
||||
Cbar_j(beta) = ( sum_{i in S_j} N_ij^beta * C_ij ) / ( sum_{i in S_j} N_ij^beta )
|
||||
S_j = { clients with N_ij > 0 and a valid local prototype for class j }
|
||||
```
|
||||
|
||||
`N_ij` is how many class-`j` training samples client `i` has. The baseline
|
||||
`original_protean` uses equal weights `1/|S_j|`. The `S_j` rule itself is an
|
||||
explicit **reproduction assumption**: no official PROTEAN code is available, so
|
||||
the participant/denominator rule is a project decision
|
||||
(`docs/research/EXPERIMENT_PROTOCOL.md`, `docs/baseline/PROTEAN_BASELINE_INVESTIGATION.md`).
|
||||
|
||||
### 1.2 The beta grid
|
||||
|
||||
`beta ∈ {0, 0.25, 0.50, 0.75, 1.00}`. The immutable specification
|
||||
(`planningawal/PROTEAN_Revisi_Lurus.md`, line 78) says, in Indonesian, that
|
||||
initial testing uses this set. It does **not** derive the spacing, does not say
|
||||
why five points were chosen, and does not justify why not a finer or wider grid.
|
||||
The choice is therefore **documented as the initial candidate set but its
|
||||
rationale is undocumented**. This exploration does not invent one. The endpoints
|
||||
have known semantics: β=0 is equal weighting over the shared `S_j`; β=1 is
|
||||
proportional to class support. β=0 is not claimed to be bitwise identical to
|
||||
`original_protean` (floating-point differences; project equivalence class B).
|
||||
|
||||
### 1.3 Experiments in the repository and in the restored results
|
||||
|
||||
| # | experiment | what it tests | runs | where |
|
||||
|---|---|---|---|---|
|
||||
| E1 | **108-run grid** | 2 datasets × 3 Dirichlet α × 3 seeds × (original + 5 betas). The main thesis experiment: does validation-selected β beat/equal the reproduced baseline on rare-class detection? | 108 | `results/<dataset>__alpha<α>__seed<s>__<mode>` (restored) |
|
||||
| E2 | **30-run 1-thread sweep** | Re-runs seed 0 only at 1 thread/process, all 2×3×5 beta cells, to test deterministic threading and to sanity-check the seed-0 β selection. No `original_protean` runs. | 30 | `results/sweep/runs/` |
|
||||
| E3 | **Reproducibility runs** | One 1-thread repeat and one 8-thread run for X-IIoTID α=0.25 seed 0 β=0, and for 5G-NIDD α=0.5 seed 0 β=0.75, to see whether thread count changes results. | 4 | `results/sweep_repro/{a_1thread_repeat,b_8thread}/` |
|
||||
| E4 | **Smoke tests** | Tiny end-to-end runs (few clients/rounds/rows) to check the pipeline; excluded from science. | a few | `results/smoke/`, `report_smoke_run.md` |
|
||||
| E5 | **Multiseed / cross-alpha / heterogeneity analyses** | Read-only reductions of E1: pooled validation curves, realized support imbalance, per-client deltas, selected-vs-original summaries. | 0 new | `scripts/analyze_*.py`, `artifacts/analysis/*multiseed*`, `*cross_alpha*`, `*partition*` |
|
||||
| E6 | **Prototype-effect analysis** | Recomputes global prototypes from fixed round-0 `{C_ij, N_ij}` snapshots at every β, without retraining, and measures displacement. | 0 new | `scripts/analyze_prototype_effect.py`, 18 surviving snapshots |
|
||||
| E7 | **Deep paired comparison** | original vs support_weighted(selected β) on test and validation, per seed/client/class. | 0 new | `scripts/deep_comparison.py`, `artifacts/analysis/deepcmp__*` |
|
||||
| E8 | **Post-hoc statistical audit** | Sign-flip tests / paired summaries over the 3 seeds; explicitly exploratory (minimum attainable p = 0.25). | 0 new | `scripts/posthoc_statistical_audit.py`, `artifacts/analysis/posthoc__*` |
|
||||
| E9 | **S_j participant-rule audit** | Counts how often `|S_j| < M` and compares the adopted `S_j` rule with a literal `1/M` hypothetical. | 0 new | `scripts/validate_sj_participant_rule.py`, `sj_*csv` |
|
||||
| E10 | **β=0 equivalence audit** | Compares `original_protean` and `support_weighted` β=0 snapshots/metrics. | 0 new | `scripts/verify_beta0_equivalence.py`, `*beta0_equivalence.csv` |
|
||||
|
||||
Restored-result inventory (measured): 108 run directories, 1,507 files, 36 runs
|
||||
per seed {0,1,2}. One run,
|
||||
`xiiotid__alpha0.5__seed0__original_protean`, is missing its five `val_*` files
|
||||
and has an older `metadata.json` without the `beta` key. That run is a baseline,
|
||||
not a β-selection candidate, so it does not affect β selection; it does mean that
|
||||
the X-IIoTID α=0.5 baseline has no validation metrics from that directory. Only
|
||||
18 prototype snapshots survived the restore (16 β=0 snapshots plus 2
|
||||
`original_protean` snapshots); the rest are represented only by committed
|
||||
derived tables.
|
||||
|
||||
### 1.4 Configs and scripts
|
||||
|
||||
Configs (frozen):
|
||||
|
||||
- `configs/datasets/datasets.yaml` — dataset paths, label columns, benign class,
|
||||
dropped labels, feature/categorical/non-feature columns.
|
||||
- `configs/experiments/experiment_protocol.yaml` — α grid, 10 clients, β
|
||||
candidates, training hyperparameters, 70/10/20 split, seeds {0,1,2},
|
||||
selection metric.
|
||||
- `configs/models/protean_cnn.yaml` — the frozen model architecture.
|
||||
|
||||
Training and analysis scripts (`scripts/`): `run_baseline.py` (single run),
|
||||
`generate_partitions.py`, `analyze_multiseed_beta.py`,
|
||||
`analyze_cross_alpha.py`, `analyze_partition_heterogeneity.py`,
|
||||
`analyze_prototype_effect.py`, `deep_comparison.py`,
|
||||
`make_comparison_figures.py`, `make_final_figures.py`,
|
||||
`posthoc_statistical_audit.py`, `validate_sj_participant_rule.py`,
|
||||
`verify_beta0_equivalence.py`, plus `scripts/sweep/{analyze_sweep,check_noise,
|
||||
compare_repro,compare_with_grid}.py`.
|
||||
|
||||
Source modules (`src/protean_research/`): `data/` (loading, preprocessing,
|
||||
splits, Dirichlet partition, manifest, rare/unseen, characterization, pipeline),
|
||||
`federated/` (client, server, round), `aggregation/` (the two aggregation modes),
|
||||
`models/` (CNN, prototypes), `evaluation/metrics.py`, `utils/`.
|
||||
|
||||
Tests (`tests/`): 75 tests, including `test_baseline_aggregation.py`,
|
||||
`test_support_weighted_aggregation.py`, `test_prototypes.py`,
|
||||
`test_federated_smoke.py`, `test_metrics.py`, `test_data_pipeline.py`,
|
||||
`test_partition.py`, `test_baseline_validation.py`, `test_prototype_effect.py`.
|
||||
They cover aggregation invariants and the baseline/β=0 equivalence, not a full
|
||||
sweep.
|
||||
|
||||
### 1.5 MAE / MAPE
|
||||
|
||||
**There is no MAE, MAPE, or any regression-error experiment or metric in this
|
||||
repository.** A full-text search finds only the phrase “mean absolute
|
||||
difference” in the sweep noise-check discussion
|
||||
(`docs/research/SWEEP_1THREAD_SEED0_CHECK.md`,
|
||||
`kisikisithesis/SWEEP_SUMMARY_REPORT.md`), which is a descriptive statistic
|
||||
comparing two runs, not a model metric. Classification is evaluated with
|
||||
accuracy, macro-F1, weighted-F1, per-class precision/recall/F1, and rare-class
|
||||
macro-F1/recall. Any statement that MAE/MAPE was used would be false.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — why the proposed method falls below the baseline
|
||||
|
||||
### 2.1 Where it falls below (measured)
|
||||
|
||||
Pooled over seeds 0–2, test rare-class macro-F1 (mean):
|
||||
|
||||
| condition | original | β=0 | β=0.25 | β=0.50 | β=0.75 | β=1.00 | lowest β | Δ lowest vs orig |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| X-IIoTID α=0.25 | 0.6328 | 0.6321 | 0.6368 | **0.6406** | 0.6272 | 0.5795 | 1.00 | **−0.0533** |
|
||||
| X-IIoTID α=0.50 | 0.6425 | 0.6443 | 0.6574 | 0.6631 | **0.6655** | 0.6599 | 0.00 | +0.0018 |
|
||||
| X-IIoTID α=0.75 | 0.6039 | 0.6059 | 0.6084 | **0.6052** | 0.6023 | 0.6024 | 0.75 | −0.0016 |
|
||||
| 5G-NIDD α=0.25 | 0.8423 | 0.8412 | 0.8293 | 0.7644 | 0.7533 | **0.7817** | 0.75 | **−0.0890** |
|
||||
| 5G-NIDD α=0.50 | 0.8805 | 0.8784 | 0.8573 | 0.8699 | 0.8754 | 0.8720 | 0.25 | **−0.0232** |
|
||||
| 5G-NIDD α=0.75 | 0.8799 | 0.8765 | 0.8861 | **0.8967** | 0.8886 | 0.8945 | 0.00 | −0.0034 |
|
||||
|
||||
Measured facts:
|
||||
|
||||
- 41 of 90 (condition, seed, β>0) cells are **below** the original on test
|
||||
rare-F1; 49 are above (the remaining are β=0 cells and FP ties).
|
||||
- The damage is concentrated at α=0.25 in both datasets. 5G-NIDD α=0.25 is
|
||||
below the baseline at **all three seeds** for β=1 (Δ −0.059, −0.104, −0.018).
|
||||
- At the *pooled-selected* β the proposed method is mostly indistinguishable
|
||||
from the baseline, because both α=0.25 conditions select β=0 by construction.
|
||||
The large negatives appear when a positive β is used, not necessarily at the
|
||||
deployed β. This nuance matters for how the result is phrased.
|
||||
|
||||
### 2.2 The three-seed grid and the single-seed sweep are different experiments
|
||||
|
||||
**Grid (3 seeds, pooled):** the validation-selected β is 0 at X-IIoTID α=0.25,
|
||||
0 at 5G-NIDD α=0.25, 0.75 at X-IIoTID α=0.5, 1.0 at 5G-NIDD α=0.5, 0.5 at
|
||||
X-IIoTID α=0.75, 0.5 at 5G-NIDD α=0.75. At the two α=0.25 cells the selected
|
||||
"proposed method" is therefore equal weighting, so its difference from the
|
||||
baseline is only floating-point divergence (measured |Δ| ≤ 0.001 in the pooled
|
||||
table).
|
||||
|
||||
**Sweep (seed 0 only, 1 thread, no baseline run):** validation-selected β is 0.75,
|
||||
0.5, 0.5 (X-IIoTID α=0.25/0.5/0.75) and 0.25, 0.75, 0.25 (5G-NIDD
|
||||
α=0.25/0.5/0.75). Within the sweep, selected-β test rare-F1 minus β=0 test
|
||||
rare-F1 is +0.027, +0.031, **−0.020**, +0.026, +0.010, +0.004 (same order). So
|
||||
the single-seed sweep shows a positive weighting effect in 5/6 cells, while the
|
||||
pooled grid selects β=0 at both α=0.25 cells. These are **not contradictory**:
|
||||
they are different selection units (one seed vs three pooled) and the sweep has
|
||||
no `original_protean` reference and a different threading/host environment.
|
||||
|
||||
Measured per-seed instability (grid): at 5G-NIDD α=0.5 the per-seed selected β
|
||||
is 1.0 / 0.0 / 1.0; at X-IIoTID α=0.25 it is 0.75 / 0.5 / 0.0. The pooled
|
||||
selection agrees with the per-seed choice in only 1–2 of 3 seeds per condition.
|
||||
The sweep's seed-0 β equals the grid's seed-0 β in 4/6 conditions. None of this
|
||||
is a significance test.
|
||||
|
||||
### 2.3 Which β step hurts most (measured)
|
||||
|
||||
Adjacent-step change in pooled validation per-client rare-F1:
|
||||
|
||||
| condition | 0→0.25 | 0.25→0.50 | 0.50→0.75 | 0.75→1.00 |
|
||||
|---|---|---|---|---|
|
||||
| X-IIoTID α=0.25 | −0.003 | −0.003 | −0.006 | **−0.047** |
|
||||
| X-IIoTID α=0.50 | +0.011 | +0.012 | +0.012 | −0.006 |
|
||||
| X-IIoTID α=0.75 | +0.003 | +0.002 | −0.004 | −0.004 |
|
||||
| 5G-NIDD α=0.25 | −0.012 | **−0.024** | −0.004 | +0.015 |
|
||||
| 5G-NIDD α=0.50 | **−0.042** | +0.030 | +0.014 | +0.004 |
|
||||
| 5G-NIDD α=0.75 | +0.012 | +0.019 | −0.018 | +0.013 |
|
||||
|
||||
The worst single step is X-IIoTID α=0.25 from 0.75 to 1.00 (−0.047 validation,
|
||||
−0.048 test) and 5G-NIDD α=0.25 from 0.25 to 0.50 (−0.024 validation, −0.065
|
||||
test). Both are sharp transitions, not a smooth trend. The response is
|
||||
non-monotone in every condition.
|
||||
|
||||
At β=1 the other test metrics move with rare-F1 (pooled deltas vs baseline):
|
||||
X-IIoTID α=0.25 rare-F1 −0.053, rare-recall −0.114, macro-F1 −0.050, accuracy
|
||||
−0.021; X-IIoTID α=0.50 +0.017 / −0.026 / +0.019 / −0.001; X-IIoTID α=0.75
|
||||
−0.002 / −0.009 / +0.005 / +0.007; 5G-NIDD α=0.25 −0.061 / −0.065 / −0.037 /
|
||||
−0.011; 5G-NIDD α=0.50 −0.009 / −0.006 / −0.004 / −0.001; 5G-NIDD α=0.75
|
||||
+0.015 / +0.000 / +0.010 / +0.001. Accuracy is nearly flat while rare-F1 moves
|
||||
by up to 0.06, so accuracy hides the effect.
|
||||
|
||||
### 2.4 Per class: what actually degrades (measured)
|
||||
|
||||
At β=1, pooled test-F1 deltas versus the baseline (mean over 3 seeds):
|
||||
|
||||
- **X-IIoTID α=0.25:** Lateral_movement −0.159, Weaponization −0.139,
|
||||
Tampering −0.106, C&C −0.036; the benign class and Reconnaissance are
|
||||
essentially flat (+0.005, +0.003). The loss is concentrated in behavioural
|
||||
attack classes, not in the majority class.
|
||||
- **5G-NIDD α=0.25:** ICMPFlood F1 −0.363 with **no recall change**
|
||||
(precision collapse), HTTPFlood −0.126 (recall −0.182), UDPFlood −0.047
|
||||
(recall −0.204), while Benign gains +0.096. This is the signature of the
|
||||
decision regions shifting toward high-support traffic and cross-class
|
||||
confusion.
|
||||
- **X-IIoTID α=0.50:** C&C −0.079, Exfiltration −0.020, but Reconnaissance
|
||||
+0.070 and Tampering +0.166; the aggregate is positive because gains and
|
||||
losses partly cancel.
|
||||
- **5G-NIDD α=0.50:** small losses (SYNFlood −0.043, SlowrateDoS −0.013) and a
|
||||
small TCPConnectScan gain (+0.034); the condition-level loss is driven by
|
||||
a few seeds, not by one class.
|
||||
|
||||
### 2.5 Per client and per seed (measured)
|
||||
|
||||
At β=1, validation per-client rare-F1 change versus the baseline (10 clients ×
|
||||
3 seeds; positive / negative client-seed cells):
|
||||
|
||||
| condition | mean Δ | improve / degrade |
|
||||
|---|---|---|
|
||||
| X-IIoTID α=0.25 | −0.059 | 12 / 15 |
|
||||
| X-IIoTID α=0.50 | +0.047 | 16 / 2 |
|
||||
| X-IIoTID α=0.75 | −0.000 | 16 / 13 |
|
||||
| 5G-NIDD α=0.25 | −0.022 | 10 / 11 |
|
||||
| 5G-NIDD α=0.50 | +0.003 | 16 / 10 |
|
||||
| 5G-NIDD α=0.75 | +0.019 | 14 / 11 |
|
||||
|
||||
Even in the best condition some clients degrade; even in the worst some
|
||||
improve. Client identities are per-seed realisations, so they are not pooled.
|
||||
|
||||
Unseen classes (attack classes with `N_ij=0` for a client; never merged with
|
||||
rare classes) also degrade at β=1. Mean recall over the union of unseen classes:
|
||||
X-IIoTID α=0.25 −0.196, α=0.50 −0.029, α=0.75 −0.009; 5G-NIDD α=0.25 −0.017,
|
||||
α=0.50 ~0.000, α=0.75 +0.000. Mean unseen F1: −0.073 (X-IIoTID α=0.25) and
|
||||
−0.082 (5G-NIDD α=0.25). Table: `exploration_v2/results/phase2_unseen.csv`.
|
||||
|
||||
### 2.6 Validation versus test, and the selection/headline mismatch (measured)
|
||||
|
||||
The deployed selection metric is the **per-client mean** of rare-class macro-F1
|
||||
on validation. The headline metric is the **global pooled** rare-class macro-F1
|
||||
on test. These are different estimands: the per-client mean gives every client
|
||||
equal weight regardless of how many rare samples it has; the global metric is
|
||||
sample-weighted.
|
||||
|
||||
| condition | validation ranking by per-client mean | validation ranking by global rare-F1 | test ranking | per-client ranking matches test? |
|
||||
|---|---|---|---|---|
|
||||
| X-IIoTID α=0.25 | 0 > .25 > .50 > .75 > 1 | **.50** > .25 > 0 > .75 > 1 | .50 > .25 > 0 > .75 > 1 | no (6/6 for global) |
|
||||
| X-IIoTID α=0.50 | .75 > 1 > .50 > .25 > 0 | .75 > .50 > 1 > .25 > 0 | .75 > .50 > 1 > .25 > 0 | yes |
|
||||
| X-IIoTID α=0.75 | .50 > .25 > .75 > 0 > 1 | .25 > 0 > .50 > .75 > 1 | .25 > 0 > .50 > 1 > .75 | partly |
|
||||
| 5G-NIDD α=0.25 | 0 > .25 > 1 > .50 > .75 | same order | same order | yes |
|
||||
| 5G-NIDD α=0.50 | **1** > .75 > 0 > .50 > .25 | **0** > .75 > 1 > .50 > .25 | 0 > .75 > 1 > .50 > .25 | no |
|
||||
| 5G-NIDD α=0.75 | .50 > 1 > .75 > .25 > 0 | same order | same order | yes |
|
||||
|
||||
Measured: the per-client-mean ranking matches the test ranking in 4/6
|
||||
conditions, the global-validation ranking in 6/6. The two clearest failures are
|
||||
exactly the two conditions with the largest proposed-vs-baseline loss:
|
||||
X-IIoTID α=0.25 (selection picks β=0, test prefers 0.50) and 5G-NIDD α=0.50
|
||||
(selection picks β=1, test prefers 0). This is a **selection-metric problem**,
|
||||
not only a weighting problem. It is the direct motivation for candidate C7.
|
||||
|
||||
Validation-to-test *level* gaps are small for the global metric (e.g. 5G-NIDD
|
||||
α=0.25 validation 0.8424 vs test 0.8423), so the mismatch is about **ranking**,
|
||||
not about a systematic validation/test scale shift.
|
||||
|
||||
### 2.7 Support heterogeneity and the participant rule (measured)
|
||||
|
||||
| condition | mean support CV | classes with `|S_j|<M` (of 9) | mean max weight share at β=1 |
|
||||
|---|---|---|---|
|
||||
| X-IIoTID α=0.25 | 1.442 | 6.3 | 0.528 |
|
||||
| X-IIoTID α=0.50 | 1.183 | 2.3 | 0.400 |
|
||||
| X-IIoTID α=0.75 | 0.881 | 1.0 | 0.284 |
|
||||
| 5G-NIDD α=0.25 | 1.302 | 5.3 | 0.454 |
|
||||
| 5G-NIDD α=0.50 | 1.225 | 1.3 | 0.414 |
|
||||
| 5G-NIDD α=0.75 | 0.916 | 1.3 | 0.298 |
|
||||
|
||||
At α=0.25, one client often holds more than half of a class's β=1 weight. Over
|
||||
the whole grid, 53/162 class-cells have `|S_j| < 10`; in those cells the mean
|
||||
top-weight share at β=1 is 0.463 versus 0.364 when all 10 clients contribute.
|
||||
The participant rule is the same for baseline and weighted modes, so `S_j`
|
||||
itself is not the cause of the *difference*; the difference is how weight is
|
||||
distributed **inside** `S_j`. What the data cannot separate: whether the losses
|
||||
come from concentration alone, from a few low-quality high-support prototypes,
|
||||
or from the retraining feedback (changing the global prototypes changes the next
|
||||
round's local alignment and therefore the local embeddings). The last is a
|
||||
hypothesis, not measured.
|
||||
|
||||
### 2.8 Prototype displacement versus detection (measured / inferred)
|
||||
|
||||
Committed round-0 snapshots give mean `||Cbar_j(β) − Cbar_j(0)||` increasing
|
||||
monotonically in β in all six conditions (e.g. X-IIoTID α=0.25: 1.48, 2.40,
|
||||
3.00, 3.42 for β = .25/.50/.75/1.0). Across the 30 condition-β cells the
|
||||
descriptive Pearson correlation between displacement and the test rare-F1 delta
|
||||
is **−0.48**: larger displacement tends to accompany worse detection in this
|
||||
grid. This is descriptive and confounded (displacement is larger exactly in the
|
||||
cells where support is most imbalanced). **Inferred, not causal:** displacement
|
||||
is a representation metric, not a quality metric. The project's own claim
|
||||
register forbids reading displacement as detection quality, and this analysis
|
||||
does not.
|
||||
|
||||
### 2.9 Reproduced baseline versus the paper (measured)
|
||||
|
||||
The paper reports “PROTEAN (Ours)” macro accuracy 92.67 / 93.62 / 93.43 on
|
||||
X-IIoTID and 85.83 / 82.50 / 79.97 on 5G-NIDD for α = 0.25 / 0.50 / 0.75. A
|
||||
macro-accuracy number is the mean per-class recall, so the reproduced baseline
|
||||
can be compared on that definition (computed from the restored
|
||||
`original_protean/test_per_class.csv`):
|
||||
|
||||
| α | X-IIoTID reproduced | X-IIoTID paper | 5G-NIDD reproduced | 5G-NIDD paper |
|
||||
|---|---|---|---|---|
|
||||
| 0.25 | 83.78 | 92.67 | 88.37 | 85.83 |
|
||||
| 0.50 | 86.56 | 93.62 | 89.76 | 82.50 |
|
||||
| 0.75 | 87.61 | 93.43 | 90.41 | 79.97 |
|
||||
|
||||
Measured gap: X-IIoTID is reproduced 5–9 points lower than the paper; 5G-NIDD is
|
||||
3–10 points higher. The direction differs by dataset. Causes are **unknown**:
|
||||
the paper's split (80/20, no validation), exact seeds, preprocessing, model
|
||||
initialisation and whether “macro accuracy” is exactly mean per-class recall are
|
||||
not fully specified or not available (no official code). All proposed-vs-baseline
|
||||
statements are therefore conditional on this reproduced baseline, not on the
|
||||
paper's numbers. This is a reproduction gap, not evidence about β.
|
||||
|
||||
### 2.10 Summary of the diagnosis
|
||||
|
||||
Measured:
|
||||
1. The proposed operator loses most at α=0.25, especially 5G-NIDD (all three
|
||||
seeds at β=1) and X-IIoTID at β≥0.75.
|
||||
2. The loss is class-specific (rare attack classes lose F1/recall; benign/high
|
||||
support classes gain), and client-specific in both directions.
|
||||
3. The response is non-monotone in β; the sharpest harmful step is 0.75→1.00
|
||||
(X-IIoTID α=0.25) and 0.25→0.50 (5G-NIDD α=0.25).
|
||||
4. Weight concentration is high exactly where the loss is high (top weight share
|
||||
0.45–0.53 at α=0.25).
|
||||
5. The deployed per-client selection metric disagrees with the global headline
|
||||
ranking in 2/6 conditions; the global validation metric agrees in 6/6.
|
||||
6. Proposal displacement grows monotonically with β, while detection does not;
|
||||
their descriptive correlation is negative.
|
||||
|
||||
Hypotheses (not measured):
|
||||
- High-support clients may have prototypes that are good for majority traffic
|
||||
but misplaced for rare attacks; down-weighting low-support clients removes
|
||||
the only rare-class evidence. This is consistent with the class pattern but
|
||||
not isolated.
|
||||
- Part of the effect is end-to-end: changing global prototypes changes the
|
||||
prototype-alignment loss in the next round, which changes the embeddings.
|
||||
A fixed-snapshot analysis cannot separate this from the direct weighting
|
||||
effect.
|
||||
- Seed-level variation (selection changes in 2/3 seeds in some conditions) may
|
||||
be larger than the between-β effect; three seeds cannot resolve it.
|
||||
@@ -0,0 +1,283 @@
|
||||
# exploration_v2 — pre-registered plan
|
||||
|
||||
Status: written before any screening or confirmatory run.
|
||||
Repository: `/home/willtanoe/project/prototype-agregation`.
|
||||
Scope: diagnostic follow-up to the completed 108-run PROTEAN beta grid.
|
||||
Nothing in `src/`, `configs/`, `tests/`, `scripts/`, `results/`,
|
||||
`artifacts/partitions/`, `planningawal/` is modified. All new material lives in
|
||||
`exploration_v2/`.
|
||||
|
||||
A short engineering smoke run (3000 rows, 2 rounds, 4 clients, X-IIoTID seed 0)
|
||||
was executed **before this file was hashed** to prove that the copied runner and
|
||||
the monkey-patched aggregator work. It is not a screening run, not a
|
||||
confirmatory run, and none of its numbers are used for ranking. The driver
|
||||
re-runs the smoke test after this plan is hashed.
|
||||
|
||||
---
|
||||
|
||||
## 1. Question
|
||||
|
||||
Phase 2 measured that the current proposed method
|
||||
(`support_weighted`, β selected on validation per-client-mean rare-class
|
||||
macro-F1) scores **below** the reproduced original PROTEAN baseline in several
|
||||
conditions, most clearly at X-IIoTID α=0.25 (β=1 test rare-F1 0.5795 vs 0.6328)
|
||||
and 5G-NIDD α=0.50 (selected β=1 test 0.8720 vs 0.8805). This exploration asks:
|
||||
|
||||
> Among a small set of pre-specified modifications to the server-side
|
||||
> aggregation, which ones improve validation rare-class macro-F1 over the
|
||||
> original baseline and over the current proposed method, and do any of them
|
||||
> keep that improvement on seeds that were never used in the analysis?
|
||||
|
||||
There is no target score. A modification that does not improve is a valid result
|
||||
and stays in the tables.
|
||||
|
||||
## 2. Frozen inputs and seeds
|
||||
|
||||
- Existing partition manifests for seeds 0, 1, 2 are used **read-only** from
|
||||
`artifacts/partitions/` for screening.
|
||||
- Seeds 0, 1, 2 are **burned for confirmation** (Phase 2 read their test
|
||||
metrics; the 108-run grid and the 30-run sweep both used them).
|
||||
- Confirmatory seeds: **3 and 4**. New manifests are generated inside
|
||||
`exploration_v2/partitions/` with the frozen procedure
|
||||
(`protean_research.data.pipeline.create_partition`,
|
||||
`per_class_dirichlet_multinomial`), never in `artifacts/partitions/`.
|
||||
- Confirmatory manifest files:
|
||||
`exploration_v2/partitions/xiiotid__alpha0.25__seed{3,4}.json`,
|
||||
`exploration_v2/partitions/5gnidd__alpha0.5__seed{3,4}.json`.
|
||||
|
||||
## 3. Screening conditions (2)
|
||||
|
||||
Chosen from the Phase 2 diagnosis, before any new result is seen:
|
||||
|
||||
| id | dataset | alpha | seed | why |
|
||||
|---|---|---|---|---|
|
||||
| S1 | xiiotid | 0.25 | 0 | most heterogeneous cell; largest β-step validation loss (0.75→1.00: −0.047); maximum weight share 0.528 |
|
||||
| S2 | 5gnidd | 0.50 | 0 | validation-selected β=1 lost to the baseline on test; deployed per-client metric and global metric disagree |
|
||||
|
||||
Screening uses these two conditions only. Both are existing frozen partitions;
|
||||
all new runs in a condition reuse the same manifest, split and initialisation
|
||||
policy, so comparisons are paired.
|
||||
|
||||
## 4. Screening variants (6) and references
|
||||
|
||||
| id | mode | fixed parameters | source |
|
||||
|---|---|---|---|
|
||||
| V1 `v_beta1.5` | `v_beta` | β=1.5 | extended grid |
|
||||
| V2 `v_shrink0.5` | `v_shrink` | β=1, λ=0.5 | shrinkage toward equal |
|
||||
| V3 `v_cap4` | `v_cap` | β=1, cap=4×median | capping |
|
||||
| V4 `v_cap2` | `v_cap` | β=1, cap=2×median | aggressive capping (expected negative) |
|
||||
| V5 `v_minsup10` | `v_minsup` | β=0, t=10 | participant-rule change (expected negative) |
|
||||
| V6 `v_logweight` | `v_logweight` | β=0 | different weight function |
|
||||
|
||||
Hyperparameters are fixed above and are **not** tuned on screening outcomes.
|
||||
|
||||
Reference runs on the screening conditions are the **existing** seed-0 results
|
||||
from the restored grid, read under identical conditions (same manifest, same
|
||||
split, same initialisation policy):
|
||||
|
||||
- `original_protean`;
|
||||
- `support_weighted` at β ∈ {0, 0.25, 0.50, 0.75, 1.00} (the current method's
|
||||
beta grid).
|
||||
|
||||
No new reference training is needed for screening.
|
||||
|
||||
Analysis-level candidates with **zero** training cost:
|
||||
|
||||
- **C7 selection metric:** re-rank the same validation files using
|
||||
`val_rare_class_macro_f1_global` instead of the deployed per-client mean.
|
||||
- **C8 finer beta grid:** reported from the existing coarse grid only; no new
|
||||
β points are run in this exploration.
|
||||
|
||||
## 5. Screening ranking metric (validation only)
|
||||
|
||||
Primary score for variant V:
|
||||
|
||||
```
|
||||
score(V) = mean over c in {S1, S2} of
|
||||
[ val_global_rare_f1(V, c, seed 0)
|
||||
- val_global_rare_f1(original, c, seed 0) ]
|
||||
```
|
||||
|
||||
where `val_global_rare_f1` is `rare_class_macro_f1` from
|
||||
`val_global_metrics.json` (global pooled validation, the same definition as the
|
||||
headline test metric). Ranking is by `score(V)`, descending. Tie-break:
|
||||
larger minimum per-condition difference, then lexical id.
|
||||
|
||||
Justification (recorded before new results): the headline metric is the global
|
||||
pooled rare-class macro-F1; Phase 2 measured that the deployed per-client mean
|
||||
ranks β differently in 2/6 conditions while the global validation metric
|
||||
matches the test ranking in 6/6. This is a metric-definition argument, not a
|
||||
test-result-driven choice.
|
||||
|
||||
Secondary sensitivity ranking: the same score computed with
|
||||
`val_rare_class_macro_f1_per_client_mean` from `val_selection.json` (the
|
||||
deployed metric). Both rankings are reported.
|
||||
|
||||
The screening analysis code reads **only** `val_*` files and logs every path it
|
||||
opens to `exploration_v2/ACCESS_LOG.txt`. It must not open any
|
||||
`test_*`, `per_client.csv` or `history.json` file.
|
||||
|
||||
## 6. Confirmatory design
|
||||
|
||||
The **top 2** variants by the primary screening score go to confirmation.
|
||||
|
||||
Confirmation conditions: **S1 and S2** (same two conditions), seeds **3 and 4**.
|
||||
Confirmation configurations per (condition, seed):
|
||||
|
||||
1. `original_protean` (baseline reference);
|
||||
2. `support_weighted` β=1.00 (canonical current method / maximal support weight);
|
||||
3. `support_weighted` β=0.50 (interior point of the current beta grid);
|
||||
4. top-1 variant (fixed hyperparameters above);
|
||||
5. top-2 variant (fixed hyperparameters above).
|
||||
|
||||
This is 5 configs × 2 conditions × 2 seeds = **20 confirmatory runs**.
|
||||
|
||||
Deviation from the literal "current proposed method with its beta grid": only
|
||||
β=0.50 and β=1.00 are run on the new seeds, not all five betas, because the
|
||||
full grid would add 12 runs and push the planned total past the conservative
|
||||
96-hour capacity (§7). The full five-beta grid is the screening reference on
|
||||
the existing seeds. This truncation is recorded here before any confirmation
|
||||
result exists.
|
||||
|
||||
## 7. Budget, duration and maximum run count
|
||||
|
||||
Measured per-run wall times from `results/sweep/summary.csv` (30 completed
|
||||
1-thread runs, seed 0):
|
||||
|
||||
| dataset | n | mean wall | min | max | mean peak RSS | max peak RSS | memory cap |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| xiiotid | 15 | 3.53 h | 2.94 h | 3.98 h | 7.02 GiB | 8.38 GiB | 11 G |
|
||||
| 5gnidd | 15 | 5.49 h | 4.47 h | 6.09 h | 10.67 GiB | 13.12 GiB | 15 G |
|
||||
| all | 30 | 4.51 h | | | | | |
|
||||
|
||||
Allowed concurrency (from the copied `run_one.sh` caps, sum ≤ 36 GiB, ≤ 3
|
||||
processes): 3 × X-IIoTID = 33 GiB; 2 × 5G-NIDD = 30 GiB; 1 × 5G-NIDD + 1 ×
|
||||
X-IIoTID = 26 GiB (a third process would be 37 GiB > 36). 5G-NIDD is never
|
||||
allowed above 2 concurrent.
|
||||
|
||||
Conservative capacity bound (2 usable slots, mean run 4.51 h):
|
||||
|
||||
```
|
||||
96 h / 4.51 h × 2 slots ≈ 42 runs
|
||||
```
|
||||
|
||||
Planned: 12 screening + 20 confirmatory = **32 new runs**; 8 of the 32 are
|
||||
X-IIoTID (S1) and 12 are 5G-NIDD (S2): screening 6+6, confirmation 10+10.
|
||||
This leaves a margin below the bound. The run list is fixed by this plan.
|
||||
|
||||
Budget clock: the first scientific run's UTC start time is written to
|
||||
`exploration_v2/BUDGET_START`; no new run may be launched after
|
||||
`BUDGET_START + 96 h`.
|
||||
|
||||
If the budget turns out to be too small, reduce in this order:
|
||||
|
||||
1. drop screening condition S2 (keep S1) → 6 screening runs;
|
||||
2. drop variants in this order: V4 `v_cap2`, V5 `v_minsup10`, V6
|
||||
`v_logweight`, V3 `v_cap4`, V1 `v_beta1.5`. Never go below 3 variants;
|
||||
the retained minimum set is V2 `v_shrink0.5`, V1 `v_beta1.5`, V3 `v_cap4`;
|
||||
3. if still too small, reduce confirmatory conditions to S1 only (10
|
||||
confirmatory runs), keeping 2 new seeds.
|
||||
|
||||
## 8. Improvement definition (confirmation)
|
||||
|
||||
For variant V and condition c ∈ {S1, S2}, seed s ∈ {3, 4}:
|
||||
|
||||
```
|
||||
d(c,s) = val_global_rare_f1(V, c, s) - val_global_rare_f1(original, c, s)
|
||||
```
|
||||
|
||||
- **Improvement over the original baseline**: mean over the four `d(c,s)` is
|
||||
strictly positive **and** every one of the four differences is strictly
|
||||
positive (same sign on every confirmatory seed and condition).
|
||||
- **No improvement / mixed**: any other outcome. Mixed is reported, never
|
||||
recoded as success.
|
||||
- Secondary paired differences vs `support_weighted` β=1.00 and β=0.50 are
|
||||
reported with mean, sample standard deviation and per-seed values. They are
|
||||
descriptive; no significance test and no superiority claim.
|
||||
|
||||
Selection margins (best minus runner-up validation score within a condition)
|
||||
are reported for the screening table. They are not used to claim a winner when
|
||||
they are smaller than between-seed spread.
|
||||
|
||||
## 9. Stop rules
|
||||
|
||||
The driver stops launching new runs and records the reason in
|
||||
`exploration_v2/ISSUES.md` and `exploration_v2/STOP_REASON` if any of:
|
||||
|
||||
1. `exploration_v2/STOP` exists;
|
||||
2. more than 20 % of finished runs have failed (failed / (done + failed)), with
|
||||
at least 5 finished runs;
|
||||
3. the 96-hour budget is exhausted;
|
||||
4. two memory-related kills (exit 137) occur in a row — then lower concurrency
|
||||
by one and continue (this is a throttle, not a full stop, unless the
|
||||
concurrency is already 1);
|
||||
5. smoke test or the unit tests fail;
|
||||
6. the pre-confirmation ranking script fails to produce a valid
|
||||
`ranking.json`.
|
||||
|
||||
Runs already in flight are allowed to finish; the driver does not kill them.
|
||||
|
||||
## 10. Freezing and honesty notes
|
||||
|
||||
- The pre-confirmation ranking file is `exploration_v2/ranking.json`. Its
|
||||
sha256 and UTC time are written to `exploration_v2/ranking.sha256` **before**
|
||||
the first confirmatory run is launched.
|
||||
- No test metric from any new run is read before that freeze. The screening
|
||||
code reads only `val_*` files.
|
||||
- After the freeze, confirmatory test metrics may be read by the final analysis
|
||||
script only.
|
||||
- Screening six variants raises the chance that the top one is lucky. The
|
||||
confirmation step on unseen seeds exists precisely because of that; the
|
||||
exploration does not adjust the plan after seeing confirmatory results.
|
||||
- Amendments after the plan hash is recorded are allowed only as dated entries
|
||||
in `exploration_v2/PLAN_AMENDMENTS.md`, each stating the reason and exactly
|
||||
what had already been seen at that point. Silent edits to this file are not
|
||||
permitted; the hash in `PLAN.sha256` is the frozen reference.
|
||||
- No statistical significance, no superiority, no universal-beta claim will be
|
||||
made. Differences are reported with sample standard deviations and per-seed
|
||||
values.
|
||||
- Every variant and every run is reported, including failures and negative
|
||||
results.
|
||||
|
||||
## 11. Exact run list
|
||||
|
||||
Screening (12):
|
||||
|
||||
```
|
||||
xiiotid__alpha0.25__seed0__v_beta__b1.5
|
||||
xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5
|
||||
xiiotid__alpha0.25__seed0__v_cap__b1__c4
|
||||
xiiotid__alpha0.25__seed0__v_cap__b1__c2
|
||||
xiiotid__alpha0.25__seed0__v_minsup__t10
|
||||
xiiotid__alpha0.25__seed0__v_logweight
|
||||
5gnidd__alpha0.5__seed0__v_beta__b1.5
|
||||
5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5
|
||||
5gnidd__alpha0.5__seed0__v_cap__b1__c4
|
||||
5gnidd__alpha0.5__seed0__v_cap__b1__c2
|
||||
5gnidd__alpha0.5__seed0__v_minsup__t10
|
||||
5gnidd__alpha0.5__seed0__v_logweight
|
||||
```
|
||||
|
||||
Confirmation (20; the two variant labels are filled from `ranking.json`):
|
||||
|
||||
```
|
||||
{d}__alpha{a}__seed{s}__original_protean
|
||||
{d}__alpha{a}__seed{s}__support_weighted__beta0.5
|
||||
{d}__alpha{a}__seed{s}__support_weighted__beta1
|
||||
{d}__alpha{a}__seed{s}__{top1_label}
|
||||
{d}__alpha{a}__seed{s}__{top2_label}
|
||||
```
|
||||
|
||||
for `(d,a) ∈ {(xiiotid,0.25),(5gnidd,0.5)}` and `s ∈ {3,4}`.
|
||||
|
||||
## 12. What will be reported
|
||||
|
||||
- Full Phase 1 inventory and Phase 2 plain-language diagnosis.
|
||||
- Plan hash, every variant, every run (including failures), wall time and peak
|
||||
memory.
|
||||
- Screening ranking table with mean and per-condition paired differences over
|
||||
the baseline and over the current method.
|
||||
- Confirmatory per-seed differences over the baseline, β=0.5 and β=1.0, with
|
||||
mean and sample standard deviation, and direction agreement.
|
||||
- Negative results and deviations with timestamps.
|
||||
- Explicit separation of measured / inferred / unknown statements.
|
||||
@@ -0,0 +1,2 @@
|
||||
2118f31b30270e1d806cf7acdac2249da625646f2d9ce3a0cee96307317c978e PLAN.md
|
||||
2026-10-30T04:07:47Z
|
||||
@@ -0,0 +1,114 @@
|
||||
# Plan amendments
|
||||
|
||||
## 2026-10-30T04:10Z — A1 (engineering only)
|
||||
|
||||
- **Reason:** `run_one_v2.sh` / `run_one_inner_v2.sh` used `$HERE/../..` as the
|
||||
repository root while `$HERE` is already `exploration_v2/`, so the first six
|
||||
wrapper attempts exited 127 before Python started.
|
||||
- **What had been seen:** the non-scientific smoke test (PASS) and six
|
||||
exit-127 wrapper failures with empty run trees. No validation or test metric
|
||||
of any screening or confirmatory run existed.
|
||||
- **Change:** repository root corrected to `$HERE/..`; failed attempt
|
||||
directories archived under `exploration_v2/results/_driver_bug_20261030T0410Z/`.
|
||||
- **Unchanged:** variants, conditions, seeds, ranking metric, budget,
|
||||
concurrency, improvement definition, stop rules, PLAN.md content (hash still
|
||||
valid for the methodological plan).
|
||||
|
||||
## 2026-10-30T04:32Z — A2 (reference runs moved in-environment)
|
||||
|
||||
- **Reason:** the plan's screening references were the restored 108-run grid,
|
||||
which was produced on a different host/library environment. The project's own
|
||||
reproducibility audit measured that a 1-thread rerun on this host is *not*
|
||||
bitwise identical to that grid: over 30 seed-0 pairs the absolute test
|
||||
rare-F1 difference has median 0.0022 and max 0.0127; a 1-thread *repeat* in
|
||||
the current environment is bitwise identical to the sweep. Pairing new
|
||||
variant runs against a restored baseline would therefore confound the
|
||||
variant effect with an environment effect of the same order as the
|
||||
differences being ranked.
|
||||
- **What had been seen:** no validation or test metric from any screening or
|
||||
confirmatory run existed. Only the non-scientific smoke test (PASS) and the
|
||||
six archived exit-127 wrapper attempts existed.
|
||||
- **Change:** two `original_protean` screening reference runs were appended to
|
||||
the front of `queue_screen.csv` (X-IIoTID α=0.25 seed 0; 5G-NIDD α=0.5 seed 0)
|
||||
so that the primary baseline is measured in the same environment and with the
|
||||
same frozen partition as the variants. The ranking script now prefers:
|
||||
1. the new in-environment original run for the baseline;
|
||||
2. the current-environment 1-thread sweep for the β-grid reference (same host,
|
||||
same partitions);
|
||||
3. the restored grid as a fallback and sensitivity reference.
|
||||
- **Cost:** +2 runs (14 screening instead of 12; 34 total instead of 32).
|
||||
Conservative capacity was ≈42 runs, so the budget still holds.
|
||||
- **Unchanged:** variants, hyperparameters, ranking metric definition, seeds,
|
||||
confirmation design, improvement definition, stop rules. The primary metric
|
||||
is still “paired validation difference versus the original baseline”.
|
||||
|
||||
## 2026-10-31T08:35Z — A3 (OOM recovery in confirmation)
|
||||
|
||||
- **Reason:** during confirmation, `xiiotid__alpha0.25__seed4__original_protean`
|
||||
and `xiiotid__alpha0.25__seed4__support_weighted__beta0.5` were killed by
|
||||
systemd cgroup OOM (`Result: oom-kill`, MemoryMax=11 GiB) after ~5m39s, twice
|
||||
each. The wrapper saw exit 143 and the driver's 20 % failure-rate stop rule
|
||||
fired. The plan's memory-kill rule says: two memory-related kills in a row →
|
||||
lower concurrency by one and continue. These are memory kills, so the throttle
|
||||
rule is the applicable one.
|
||||
- **What had been seen:** 14/14 screening runs done; ranking frozen at
|
||||
05:03:55Z; 5 confirmation runs finished (3 seed-3 references); the two failed
|
||||
runs produced **zero-byte stdout/stderr/time files and no result artifacts**.
|
||||
No validation or test metric from the failed attempts existed, and none was
|
||||
read.
|
||||
- **Change:**
|
||||
1. the two OOM-killed attempts were archived to
|
||||
`results/attempts/<run>__attempt2` and requeued as clean directories;
|
||||
2. `max_procs` lowered from 3 to 2 (memory throttle);
|
||||
3. `run_one_v2.sh` now queries the transient scope's `Result` and records a
|
||||
cgroup OOM as exit 137, so the driver's throttle logic sees memory kills;
|
||||
4. the failure-rate stop is skipped when the last two exits were memory kills,
|
||||
so the throttle rule wins over the full stop.
|
||||
- **Retry accounting:** this gives the two environmental OOM victims one more
|
||||
attempt than the nominal "one retry" rule. They are references, not variants,
|
||||
and no result was ever produced; the deviation is recorded here rather than
|
||||
silently hidden.
|
||||
- **Unchanged:** ranking (frozen), variants, seeds, metrics, improvement
|
||||
definition, confirmation design, 96 h budget.
|
||||
|
||||
## 2026-10-31T09:50Z — A4 (OOM prevention: cap, concurrency, host guard)
|
||||
|
||||
- **Reason:** three seed-4 confirmation reference runs were killed by
|
||||
`oom-kill` inside 11 GiB systemd scopes; the user asked explicitly to prevent
|
||||
further OOM kills. Memory safety is an operational setting, not a scientific
|
||||
parameter.
|
||||
- **What had been seen:** 14/14 screening done, ranking frozen, 3/20
|
||||
confirmation done, three seed-4 references OOM-killed with zero-byte outputs.
|
||||
No new test metric had been read.
|
||||
- **Changes:**
|
||||
1. X-IIoTID per-run systemd cap raised from 11 GiB to **13 GiB** (5G-NIDD
|
||||
stays 15 GiB). Two concurrent X-IIoTID runs therefore request 26 GiB,
|
||||
still below the 36 GiB campaign budget.
|
||||
2. `MAX_PROCS` fixed at **2** (not 3).
|
||||
3. New host-level guard: the driver refuses to launch unless
|
||||
`/proc/meminfo MemAvailable` is at least **12 GiB**; this prevents starting
|
||||
a run while another service is squeezing the host.
|
||||
4. The wrapper maps a cgroup `oom-kill` to exit 137; two consecutive memory
|
||||
kills lower `max_procs` to 1 and continue.
|
||||
- **Unchanged:** ranking (frozen), variants, seeds, metrics, improvement
|
||||
definition, 96 h budget, total run list.
|
||||
|
||||
## 2026-10-31T14:12Z — A5 (retry unit-name collision, not a new OOM)
|
||||
|
||||
- **Reason:** the 14:06Z failures were **not** new OOM kills. A failed/OOM-killed
|
||||
transient systemd scope keeps its deterministic unit name loaded, so
|
||||
`systemd-run --unit=<same name>` refused to start the retry with “Unit … was
|
||||
already loaded”. The wrapper's new OOM check then read the *old* scope's
|
||||
`Result=oom-kill` and mislabelled the failed start as 137. This consumed the
|
||||
retry and tripped the 20 % failure-rate stop.
|
||||
- **What had been seen:** 14/14 screening; 5/20 confirmation (all of seed-3 S1);
|
||||
ranking frozen; failed retries had zero-byte logs, no artifacts, no metrics.
|
||||
- **Change:**
|
||||
1. `run_one_v2.sh` now runs `systemctl --user reset-failed <unit>.scope` and a
|
||||
one-second pause before every launch, so a reused unit name is free;
|
||||
2. if `stderr.log` contains “Failed to start transient scope unit”, the wrapper
|
||||
does **not** map the old `Result` to an OOM; it records a failed start
|
||||
instead.
|
||||
- **Recovery:** the three blocked seed-4 reference attempts were archived
|
||||
(`attempt2`/`attempt4`), requeued, and are running with the 13 GiB cap.
|
||||
- **Unchanged:** ranking, variants, seeds, metrics, budget, improvement rule.
|
||||
@@ -0,0 +1,34 @@
|
||||
# PLAN self-check (written before the plan hash is recorded)
|
||||
|
||||
Re-read `exploration_v2/PLAN.md` and checked each required item:
|
||||
|
||||
| requirement | where satisfied | verdict |
|
||||
|---|---|---|
|
||||
| at most 8 variants screened | PLAN §4: 6 run-based (V1–V6) + 2 analysis-level (C7, C8) = 8 | PASS |
|
||||
| documented drop order if budget too small | PLAN §7: drop S2 first; then V4, V5, V6, V3, V1 down to 3; then one confirmation condition | PASS |
|
||||
| reference runs: original + current method beta grid, identical conditions | PLAN §4 (screening: existing seed-0 grid, same manifests/splits); PLAN §6 + deviation note for the truncated confirmation grid (β=0.5, 1.0) | PASS, with the truncation stated as a deviation before any confirmation result |
|
||||
| per-run duration estimate from sweep logs | PLAN §7: xiiotid mean 3.53 h, 5gnidd mean 5.49 h, all mean 4.51 h, from `results/sweep/summary.csv` | PASS |
|
||||
| maximum runs at allowed concurrency within 96 h | PLAN §7: conservative bound ≈42 runs; planned 32 | PASS |
|
||||
| exact validation ranking metric | PLAN §5: mean over S1/S2 of paired difference in `val_rare_class_macro_f1_global` vs original; tie-break defined | PASS |
|
||||
| screening conditions and seeds | PLAN §3: S1 xiiotid α=0.25 seed 0; S2 5gnidd α=0.5 seed 0 | PASS |
|
||||
| separate confirmatory seeds | PLAN §2/§6: seeds 3 and 4, new manifests inside exploration_v2/partitions | PASS |
|
||||
| top 2 variants go to confirmation | PLAN §6 | PASS |
|
||||
| improvement definition | PLAN §8: positive mean paired difference AND strictly positive on all four confirmation pairs | PASS |
|
||||
| no-improvement definition | PLAN §8: any other outcome, mixed reported separately | PASS |
|
||||
| stop rules | PLAN §9: STOP file, >20 % failure, budget exhausted, two consecutive memory kills → throttle, smoke/ranking failure | PASS |
|
||||
| note that many variants raise luck risk | PLAN §10 | PASS |
|
||||
| amendment rule | PLAN §10: dated entries in PLAN_AMENDMENTS.md only | PASS |
|
||||
| no test metrics read before ranking freeze | PLAN §5/§10; ranking script restricted to val_* with ACCESS_LOG | PASS |
|
||||
| all new outputs under exploration_v2 | PLAN header; runner defaults forced inside exploration_v2 | PASS |
|
||||
| new seeds via frozen partition procedure | PLAN §2; `make_manifest_v2.py` calls the project's `create_partition` | PASS |
|
||||
| one thread per process | PLAN §7 and the copied `run_one.sh` capping mechanism; `thread1_launcher.py` pins torch | PASS |
|
||||
| memory caps ≤36 GiB and ≤3 processes | PLAN §7; driver scheduler enforces both | PASS |
|
||||
| all new variants implemented only as exploration_v2 copies with unit tests | PLAN header; `variants.py`, `run_variant.py`, `tests/test_variants.py` (14 tests) | PASS |
|
||||
|
||||
Open caveat recorded deliberately: a non-scientific engineering smoke run was
|
||||
executed before this self-check (3000 rows, 2 rounds, 4 clients). No screening
|
||||
or confirmatory run has been launched, no new run's test metric has been read,
|
||||
and no ranking decision depends on the smoke numbers. The driver repeats the
|
||||
smoke after the hash.
|
||||
|
||||
Decision: proceed to `sha256sum PLAN.md > PLAN.sha256` and start the driver.
|
||||
@@ -0,0 +1,45 @@
|
||||
# exploration_v2
|
||||
|
||||
Diagnostic follow-up to the completed 108-run PROTEAN beta grid. Everything in
|
||||
this directory is new; the tracked research code, configs, tests, scripts,
|
||||
results, partition manifests and the immutable research specification are
|
||||
untouched.
|
||||
|
||||
## Layout
|
||||
|
||||
| path | purpose |
|
||||
|---|---|
|
||||
| `PLAN.md` | pre-registered plan (hash in `PLAN.sha256`) |
|
||||
| `PLAN_CHECK.md` | self-check against the task constraints |
|
||||
| `CANDIDATES.md` | Phase 3 candidate catalogue |
|
||||
| `scripts/` | copied runner, variant implementations, ranking/analysis, driver |
|
||||
| `tests/` | unit tests for the variants (baseline and β=0 unchanged) |
|
||||
| `queue_screen.csv` | 12 screening runs |
|
||||
| `queue_confirm.csv` | generated after the ranking freeze (20 runs) |
|
||||
| `partitions/` | new-seed manifests (seeds 3 and 4) |
|
||||
| `results/runs/` | per-run outputs, logs, COMPLETE markers |
|
||||
| `analysis/` | final CSV tables |
|
||||
| `REPORT_DATA.md` | all generated tables (written after confirmation) |
|
||||
| `REPORT.md` | narrative report (Phase 6) |
|
||||
| `ACCESS_LOG.txt` | every file opened by the validation-only ranking script |
|
||||
| `HEARTBEAT`, `state.json`, `summary.csv` | driver state |
|
||||
| `ISSUES.md` | failures, deviations and permission problems |
|
||||
| `STOP`, `DONE` | stop request / completion marker |
|
||||
|
||||
## Entry points
|
||||
|
||||
```bash
|
||||
# start / resume the detached driver in tmux session explore_v2
|
||||
bash exploration_v2/resume.sh
|
||||
|
||||
# short status (returns immediately)
|
||||
bash exploration_v2/status.sh
|
||||
|
||||
# manual re-run of one stage (only when the driver is not running)
|
||||
.venv/bin/python exploration_v2/scripts/rank_screening.py
|
||||
.venv/bin/python exploration_v2/scripts/analyze_results.py
|
||||
```
|
||||
|
||||
The driver is idempotent: it reconstructs queue state from `COMPLETE`,
|
||||
`.failed`, `.running` and live systemd scopes, retries a failed run once from a
|
||||
clean directory, and never kills a process it did not start.
|
||||
@@ -0,0 +1,662 @@
|
||||
# exploration_v2 — final report
|
||||
|
||||
Status: **complete**. The driver finished on 2026-11-01T22:35:36Z with
|
||||
**34/34 scientific runs done, 0 terminal failures**, in **66.4 h** of the 96 h
|
||||
budget (`DONE` has `"status": "complete"`). This narrative covers Phase 1
|
||||
(inventory), Phase 2 (diagnosis), the pre-registered design, and the screening
|
||||
and confirmatory results. All numeric tables are in
|
||||
`exploration_v2/REPORT_DATA.md` and `exploration_v2/analysis/*.csv`.
|
||||
|
||||
Plan hash: `2118f31b30270e1d806cf7acdac2249da625646f2d9ce3a0cee96307317c978e`
|
||||
(recorded 2026-10-30T04:07:47Z in `exploration_v2/PLAN.sha256`).
|
||||
Ranking hash: `f43ebc762d1512c5decfda51f31bef7f1d089a13156e8e3c3d7eae2982b054d3`
|
||||
(recorded 2026-10-31T05:03:55Z in `exploration_v2/ranking.sha256`, before any
|
||||
confirmatory run).
|
||||
|
||||
Labels: **measured** = read/recomputed from a file; **inferred** = a reading of
|
||||
measured values; **unknown** = not established.
|
||||
|
||||
---
|
||||
|
||||
## 1. Phase 1 — what the repository contains and what each experiment tests
|
||||
|
||||
### 1.1 The method under study
|
||||
|
||||
PROTEAN is a federated intrusion detector. Ten clients train a CNN locally and
|
||||
send the server (a) model weights and (b) one **prototype per locally observed
|
||||
class** — the mean embedding of that class's training samples. The server
|
||||
aggregates the local prototypes into one global prototype per class, and
|
||||
classification is nearest global prototype. The thesis changes only the
|
||||
server-side aggregation:
|
||||
|
||||
```
|
||||
Cbar_j(beta) = sum_{i in S_j} N_ij^beta C_ij / sum_{i in S_j} N_ij^beta
|
||||
S_j = { clients with N_ij > 0 and a valid local prototype for class j }
|
||||
```
|
||||
|
||||
`N_ij` is the class-specific training support. The baseline
|
||||
(`original_protean`) uses equal weights `1/|S_j|`. The `S_j` participant rule is
|
||||
an explicit reproduction assumption, because no official PROTEAN code is
|
||||
available. `N_ij` is support, not quality; nothing here assumes a larger
|
||||
support means a better prototype.
|
||||
|
||||
### 1.2 The beta grid
|
||||
|
||||
The candidates are β ∈ {0, 0.25, 0.50, 0.75, 1.00}. The immutable specification
|
||||
(`planningawal/PROTEAN_Revisi_Lurus.md`, line 78) names this set as the initial
|
||||
test grid. It gives **no derivation of the spacing and no rationale for why
|
||||
these five points** rather than a finer or wider grid. The endpoints have known
|
||||
semantics (β=0 equal weighting; β=1 support-proportional), but the choice of
|
||||
the intermediate points is **undocumented**. This report does not invent a
|
||||
rationale.
|
||||
|
||||
### 1.3 Experiments (measured inventory)
|
||||
|
||||
| experiment | what it tests | runs | evidence |
|
||||
|---|---|---|---|
|
||||
| 108-run grid | 2 datasets × 3 α × 3 seeds × (baseline + 5 β): does validation-selected β change rare-class detection? | 108 | restored `results/` |
|
||||
| 30-run 1-thread sweep | seed 0 only, 2×3×5 β cells, deterministic threading and seed-0 selection | 30 | `results/sweep/` |
|
||||
| reproducibility runs | 1-thread repeat vs 8-thread on two cells | 4 | `results/sweep_repro/` |
|
||||
| smoke tests | pipeline sanity only, excluded from science | several | `results/smoke/`, `report_smoke_run.md` |
|
||||
| multiseed / cross-alpha / heterogeneity analyses | reductions of the grid | 0 | `scripts/analyze_*.py`, `artifacts/analysis/*` |
|
||||
| prototype-effect analysis | recomputes prototypes from fixed round-0 `{C_ij,N_ij}` snapshots | 0 | `scripts/analyze_prototype_effect.py` |
|
||||
| deep paired comparison | original vs selected-β per seed/client/class | 0 | `scripts/deep_comparison.py` |
|
||||
| post-hoc audit | exploratory sign-flip tests, n=3 | 0 | `scripts/posthoc_statistical_audit.py` |
|
||||
| `S_j` audit | how often `|S_j| < M`; literal `1/M` comparison | 0 | `scripts/validate_sj_participant_rule.py` |
|
||||
| β=0 equivalence | baseline vs β=0 snapshots/metrics | 0 | `scripts/verify_beta0_equivalence.py` |
|
||||
|
||||
Restored results: 108 directories, 1,507 files, 36 per seed {0,1,2}. One
|
||||
baseline run (`xiiotid__alpha0.5__seed0__original_protean`) lacks its five
|
||||
`val_*` files and has an older metadata schema; it is not used for β selection.
|
||||
Only 18 prototype snapshots survived the restore; most displacement claims rely
|
||||
on the committed derived tables.
|
||||
|
||||
Configs: `configs/datasets/datasets.yaml`, `configs/experiments/
|
||||
experiment_protocol.yaml`, `configs/models/protean_cnn.yaml`.
|
||||
Scripts: `scripts/{run_baseline,generate_partitions,analyze_multiseed_beta,
|
||||
analyze_cross_alpha,analyze_partition_heterogeneity,analyze_prototype_effect,
|
||||
deep_comparison,make_comparison_figures,make_final_figures,
|
||||
posthoc_statistical_audit,validate_sj_participant_rule,
|
||||
verify_beta0_equivalence}.py` and `scripts/sweep/*.py`.
|
||||
Tests: 75 tests covering aggregation invariants, the data pipeline, metrics and
|
||||
smoke training.
|
||||
|
||||
### 1.4 MAE / MAPE
|
||||
|
||||
**No MAE, MAPE or any regression-error experiment or metric exists in this
|
||||
repository.** A full-text search finds only the phrase “mean absolute
|
||||
difference” in the sweep noise-check text, which compares two runs and is not a
|
||||
model metric. Evaluation uses accuracy, macro-F1, weighted-F1, per-class
|
||||
precision/recall/F1, and rare-class macro-F1/recall. Saying otherwise would be
|
||||
false.
|
||||
|
||||
---
|
||||
|
||||
## 2. Phase 2 — why the proposed method scores below the baseline
|
||||
|
||||
All numbers below are **measured** from the restored grid / committed tables;
|
||||
tables are in `exploration_v2/results/phase2_*.csv` and the long form in
|
||||
`exploration_v2/PHASE12_ANALYSIS.md`.
|
||||
|
||||
### 2.1 Where it loses
|
||||
|
||||
Pooled test rare-class macro-F1 over seeds 0–2:
|
||||
|
||||
| condition | original | β=0 | β=0.25 | β=0.50 | β=0.75 | β=1.00 | worst β | Δ worst vs orig |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| X-IIoTID α=0.25 | 0.6328 | 0.6321 | 0.6368 | **0.6406** | 0.6272 | 0.5795 | 1.00 | **−0.0533** |
|
||||
| X-IIoTID α=0.50 | 0.6425 | 0.6443 | 0.6574 | 0.6631 | **0.6655** | 0.6599 | 0.00 | +0.0018 |
|
||||
| X-IIoTID α=0.75 | 0.6039 | 0.6059 | 0.6084 | **0.6052** | 0.6023 | 0.6024 | 0.75 | −0.0016 |
|
||||
| 5G-NIDD α=0.25 | 0.8423 | 0.8412 | 0.8293 | 0.7644 | 0.7533 | **0.7817** | 0.75 | **−0.0890** |
|
||||
| 5G-NIDD α=0.50 | 0.8805 | 0.8784 | 0.8573 | 0.8699 | 0.8754 | 0.8720 | 0.25 | **−0.0232** |
|
||||
| 5G-NIDD α=0.75 | 0.8799 | 0.8765 | 0.8861 | **0.8967** | 0.8886 | 0.8945 | 0.00 | −0.0034 |
|
||||
|
||||
41 of 90 (condition, seed, β>0) cells are below the original; 49 are above.
|
||||
5G-NIDD α=0.25 is below at all three seeds for β=1 (Δ −0.059, −0.104, −0.018).
|
||||
At the **pooled-selected** β the proposed method is ~equal to the baseline at
|
||||
both α=0.25 cells because those cells select β=0; the large losses appear when
|
||||
a positive β is used. This distinction must be kept in every claim.
|
||||
|
||||
### 2.2 The three-seed grid and the single-seed sweep are separate evidence
|
||||
|
||||
- Grid (3 seeds, pooled): selected β = 0, 0.75, 0.50 (X-IIoTID α = .25/.50/.75)
|
||||
and 0, 1.00, 0.50 (5G-NIDD). At both α=0.25 cells the selected method is equal
|
||||
weighting, so its difference from the baseline is floating-point only.
|
||||
- Sweep (seed 0, 1 thread, no baseline run): selected β = 0.75, 0.50, 0.50 and
|
||||
0.25, 0.75, 0.25. Within the sweep, selected-β minus β=0 test rare-F1 is
|
||||
+0.027, +0.031, **−0.020**, +0.026, +0.010, +0.004. So the single seed gives a
|
||||
positive weighting effect in 5/6 cells, unlike the pooled grid at α=0.25.
|
||||
They are not contradictory: different selection units, and the sweep has no
|
||||
`original_protean` reference. Per-seed grid selections are unstable (e.g.
|
||||
5G-NIDD α=0.50: 1.0 / 0.0 / 1.0; X-IIoTID α=0.25: 0.75 / 0.5 / 0.0).
|
||||
|
||||
### 2.3 Which β step hurts most
|
||||
|
||||
Validation per-client rare-F1 adjacent-step change:
|
||||
|
||||
| condition | 0→.25 | .25→.50 | .50→.75 | .75→1.00 |
|
||||
|---|---|---|---|---|
|
||||
| X-IIoTID α=0.25 | −0.003 | −0.003 | −0.006 | **−0.047** |
|
||||
| X-IIoTID α=0.50 | +0.011 | +0.012 | +0.012 | −0.006 |
|
||||
| X-IIoTID α=0.75 | +0.003 | +0.002 | −0.004 | −0.004 |
|
||||
| 5G-NIDD α=0.25 | −0.012 | **−0.024** | −0.004 | +0.015 |
|
||||
| 5G-NIDD α=0.50 | **−0.042** | +0.030 | +0.014 | +0.004 |
|
||||
| 5G-NIDD α=0.75 | +0.012 | +0.019 | −0.018 | +0.013 |
|
||||
|
||||
The worst steps are X-IIoTID α=0.25 0.75→1.00 (−0.047 validation, −0.048 test)
|
||||
and 5G-NIDD α=0.25 0.25→0.50 (−0.024 validation, −0.065 test). Response is
|
||||
non-monotone everywhere.
|
||||
|
||||
At β=1 the other metrics move with the same sign as rare-F1 (pooled test deltas
|
||||
versus the baseline):
|
||||
|
||||
| condition | rare-F1 | rare-recall | macro-F1 | accuracy |
|
||||
|---|---|---|---|---|
|
||||
| X-IIoTID α=0.25 | −0.053 | −0.114 | −0.050 | −0.021 |
|
||||
| X-IIoTID α=0.50 | +0.017 | −0.026 | +0.019 | −0.001 |
|
||||
| X-IIoTID α=0.75 | −0.002 | −0.009 | +0.005 | +0.007 |
|
||||
| 5G-NIDD α=0.25 | −0.061 | −0.065 | −0.037 | −0.011 |
|
||||
| 5G-NIDD α=0.50 | −0.009 | −0.006 | −0.004 | −0.001 |
|
||||
| 5G-NIDD α=0.75 | +0.015 | +0.000 | +0.010 | +0.001 |
|
||||
|
||||
The key asymmetry: in X-IIoTID α=0.50 rare-F1 rises while rare-recall falls
|
||||
(+precision, −recall). Overall accuracy barely moves even when rare-F1 moves by
|
||||
0.05–0.06, which is why accuracy alone hides the effect.
|
||||
|
||||
### 2.4 Per class, per client, per seed
|
||||
|
||||
- X-IIoTID α=0.25 at β=1: Lateral_movement −0.159 F1, Weaponization −0.139,
|
||||
Tampering −0.106, C&C −0.036; benign +0.005, Reconnaissance +0.003.
|
||||
- 5G-NIDD α=0.25 at β=1: ICMPFlood −0.363 F1 with **no recall change**
|
||||
(precision collapse), HTTPFlood −0.126 (recall −0.182), UDPFlood −0.047
|
||||
(recall −0.204); benign +0.096. The decision regions shift toward
|
||||
high-support traffic.
|
||||
- X-IIoTID α=0.50 at β=1: C&C −0.079, Exfiltration −0.020, but
|
||||
Reconnaissance +0.070, Tampering +0.166; gains and losses partly cancel.
|
||||
- Per-client β=1 validation deltas: worst condition X-IIoTID α=0.25 mean −0.059
|
||||
(12 client-seed cells improve, 15 degrade); best X-IIoTID α=0.50 +0.047
|
||||
(16 improve, 2 degrade). Even the worst condition has improving clients and
|
||||
the best has degrading clients. Client identities are per-seed realisations.
|
||||
- Unseen-class behaviour (attack classes with `N_ij=0` for a client; **not**
|
||||
merged with rare classes): at β=1 the mean recall over the union of unseen
|
||||
classes falls by 0.196 on X-IIoTID α=0.25, 0.029 on X-IIoTID α=0.50, 0.009 on
|
||||
X-IIoTID α=0.75, 0.017 on 5G-NIDD α=0.25, and is ~0 on the other two
|
||||
conditions; mean unseen F1 falls by 0.073 on X-IIoTID α=0.25 and 0.082 on
|
||||
5G-NIDD α=0.25. The weighting also damages classes a client never trained on,
|
||||
not only its two designated rare classes. Full table:
|
||||
`exploration_v2/results/phase2_unseen.csv`.
|
||||
|
||||
### 2.5 Validation vs test and the selection/headline mismatch
|
||||
The deployed selector maximises the **per-client mean** validation rare-F1; the
|
||||
headline is the **global pooled** test rare-F1. The two rankings agree with the
|
||||
test ranking in 4/6 and 6/6 conditions respectively. The two failures are the
|
||||
two conditions with the largest proposed-vs-baseline loss:
|
||||
|
||||
- X-IIoTID α=0.25: per-client selector picks β=0; global validation (and test)
|
||||
prefer β=0.50.
|
||||
- 5G-NIDD α=0.50: per-client selector picks β=1; global validation (and test)
|
||||
prefer β=0 (the baseline).
|
||||
|
||||
Validation-to-test *levels* are close for the global metric (e.g. 5G-NIDD
|
||||
α=0.25 validation 0.8424 vs test 0.8423), so the problem is ranking, not a
|
||||
global scale shift. This is the direct motivation for the selection-metric
|
||||
candidate.
|
||||
|
||||
### 2.6 Support heterogeneity and the participant rule
|
||||
|
||||
| condition | mean support CV | classes `|S_j|<M` (of 9) | mean max weight share at β=1 |
|
||||
|---|---|---|---|
|
||||
| X-IIoTID α=0.25 | 1.442 | 6.3 | 0.528 |
|
||||
| X-IIoTID α=0.50 | 1.183 | 2.3 | 0.400 |
|
||||
| X-IIoTID α=0.75 | 0.881 | 1.0 | 0.284 |
|
||||
| 5G-NIDD α=0.25 | 1.302 | 5.3 | 0.454 |
|
||||
| 5G-NIDD α=0.50 | 1.225 | 1.3 | 0.414 |
|
||||
| 5G-NIDD α=0.75 | 0.916 | 1.3 | 0.298 |
|
||||
|
||||
At α=0.25 one client often holds more than half of a class's β=1 weight.
|
||||
53/162 class-cells have `|S_j|<10`; their mean top-weight share is 0.463 versus
|
||||
0.364 when all clients contribute. Both modes share the same `S_j`, so the
|
||||
participant rule is not the cause of the *difference*; the weight distribution
|
||||
inside `S_j` is.
|
||||
|
||||
### 2.7 Displacement vs detection
|
||||
|
||||
Mean `||Cbar_j(β)−Cbar_j(0)||` on fixed round-0 snapshots rises monotonically
|
||||
with β in all six conditions (e.g. X-IIoTID α=0.25: 1.48, 2.40, 3.00, 3.42).
|
||||
Across the 30 condition-β cells the descriptive Pearson correlation between
|
||||
displacement and test rare-F1 delta is **−0.48**. This is descriptive and
|
||||
confounded; displacement is a representation metric, not detection quality.
|
||||
**Inferred, not causal.**
|
||||
|
||||
### 2.8 Reproduced baseline vs the paper
|
||||
|
||||
Paper “PROTEAN (Ours)” macro accuracy (mean per-class recall), as quoted in
|
||||
`kisikisithesis/RESTORE_VERIFICATION_REPORT.md` §12 (the paper PDF is not in the
|
||||
repository), vs the reproduced baseline's mean per-class recall:
|
||||
|
||||
| α | X-IIoTID reproduced | paper | 5G-NIDD reproduced | paper |
|
||||
|---|---|---|---|---|
|
||||
| 0.25 | 83.78 | 92.67 | 88.37 | 85.83 |
|
||||
| 0.50 | 86.56 | 93.62 | 89.76 | 82.50 |
|
||||
| 0.75 | 87.61 | 93.43 | 90.41 | 79.97 |
|
||||
|
||||
X-IIoTID reproduces 5–9 points below the paper; 5G-NIDD 3–10 points above. The
|
||||
cause is **unknown** (split, seeds, preprocessing and the exact definition of
|
||||
“macro accuracy” are not fully specified; no official code). Every
|
||||
proposed-vs-baseline statement is conditional on this reproduced baseline.
|
||||
|
||||
### 2.9 Diagnosis summary
|
||||
|
||||
Measured: the loss is concentrated at α=0.25 (5G-NIDD at all seeds for β=1);
|
||||
it is class- and client-specific; response is non-monotone; weight
|
||||
concentration is highest exactly where the loss is highest; the deployed
|
||||
selection metric disagrees with the global headline in 2/6 conditions while
|
||||
global validation agrees in 6/6; displacement grows monotonically while
|
||||
detection does not.
|
||||
Hypotheses (not measured): high-support prototypes may be good for majority
|
||||
traffic but misplaced for rare attacks; end-to-end prototype-alignment feedback
|
||||
may amplify the direct weighting effect; three seeds cannot resolve the
|
||||
between-β effect.
|
||||
|
||||
---
|
||||
|
||||
## 3. Phase 3 — candidate modifications
|
||||
|
||||
Full catalogue with mechanism, motivating evidence, definition change, cost and
|
||||
failure modes: `exploration_v2/CANDIDATES.md`. Summary:
|
||||
|
||||
| id | mechanism | changes the method definition? | expected |
|
||||
|---|---|---|---|
|
||||
| V1 β=1.5 | extended β grid, stronger concentration | no (same operator, wider range) | may help where β=1 was the boundary; likely hurts α=0.25 |
|
||||
| V2 shrink λ=0.5 | `w = 0.5·equal + 0.5·N^β` | yes (new operator) | bound the concentration tail |
|
||||
| V3 cap 4×median | clip raw weights at 4× median | yes (new operator) | bound single-client dominance |
|
||||
| V4 cap 2×median | tighter cap | yes (same family) | **expected negative** (approaches equal weighting) |
|
||||
| V5 min support 10 | drop clients with `N_ij<10`, equal mean | yes (participant-rule change) | **expected negative** (removes rare evidence) |
|
||||
| V6 log weight | `w ∝ log(1+N)` | yes (new weight function) | may over-equalise |
|
||||
| C7 global selection metric | select β by global validation rare-F1 | no (selection procedure only) | fixes the two ranking mismatches |
|
||||
| C8 finer β grid | more β points | no (candidate set only) | not run; coarse-grid noise is already large |
|
||||
|
||||
New implementations are **copies inside `exploration_v2/`**; the original code is
|
||||
untouched. 14 unit tests verify that `original_protean` is bit-for-bit the
|
||||
project implementation, that `support_weighted` (including β=0) delegates
|
||||
exactly, and that a single contributor, equal supports, missing classes and
|
||||
invalid parameters behave as documented.
|
||||
|
||||
**Exploratory result for C7 on the old grid (measured, not confirmatory).**
|
||||
Selecting β by validation *global* rare-F1 instead of the deployed per-client
|
||||
mean changes the selected β in X-IIoTID α=0.25 (0→0.50) and 5G-NIDD α=0.50
|
||||
(1.00→0). Mean test rare-F1 difference versus the original baseline across the
|
||||
six conditions is +0.0082 with global selection versus +0.0052 with the deployed
|
||||
selection; the 5G-NIDD α=0.50 loss shrinks from −0.0086 to −0.0021 and the
|
||||
X-IIoTID α=0.25 difference turns from −0.0007 to +0.0078. These are descriptive
|
||||
numbers from the same three burned seeds, not a confirmation, and they must not
|
||||
be presented as a new-run result.
|
||||
|
||||
---
|
||||
|
||||
## 4. Phase 4/5 — pre-registered execution
|
||||
|
||||
- `PLAN.md` frozen at 2026-10-30T04:07:47Z (hash above).
|
||||
- Screening: 2 conditions (X-IIoTID α=0.25 seed 0; 5G-NIDD α=0.5 seed 0),
|
||||
6 variants. Screening references: the current-environment original baseline
|
||||
(2 runs, amendment A2) and the current-environment 1-thread β grid from
|
||||
`results/sweep/`; restored-grid values are a sensitivity reference.
|
||||
- Ranking metric: mean over the two conditions of the paired validation
|
||||
difference in **global** rare-class macro-F1 versus the original. Secondary:
|
||||
the deployed per-client-mean metric.
|
||||
- Confirmation: top 2 variants + original + β=0.5 + β=1 on **new seeds 3 and 4**
|
||||
in both conditions (20 runs). All new-seed manifests were generated with the
|
||||
frozen partition procedure inside `exploration_v2/partitions/`.
|
||||
- Video/audio hyperparameters are fixed a priori; no tuning on screening
|
||||
outcomes. Budget: 34 planned runs, conservative capacity ≈42 at the allowed
|
||||
concurrency, 96 h cap.
|
||||
- Deviations: A1 (driver path bug, no scientific run started) and A2
|
||||
(in-environment baseline references). Both dated in
|
||||
`exploration_v2/PLAN_AMENDMENTS.md`; engineering fixes are in `ISSUES.md`.
|
||||
|
||||
**Pairing verification (measured).** For each screening condition, all seven
|
||||
runs (baseline + six variants) have an identical manifest content hash, an
|
||||
identical preprocessing hash, a byte-identical round-0 prototype snapshot, and
|
||||
an identical `N_ij` support matrix. The round-0 snapshot is recorded before the
|
||||
first aggregation, so identical snapshots confirm that the only difference
|
||||
between the runs is the aggregation operator. Hashes:
|
||||
`exploration_v2/analysis/screening_pairing_check.csv`.
|
||||
|
||||
<!-- AUTO_RESULTS_START -->
|
||||
## 5. Results of the new runs
|
||||
|
||||
### 5.1 Screening ranking (validation only)
|
||||
|
||||
Top-1 minus top-2 validation score (selection margin): 0.020278 (top2 = ['v_shrink__b1__lam0.5', 'v_cap__b1__c4']).
|
||||
|
||||
Score = mean over S1,S2 of the paired validation difference in global rare-class macro-F1 versus the in-environment original baseline. `rank_secondary` uses the deployed per-client-mean metric.
|
||||
|
||||
| rank | variant | β | λ | cap | min N | score | min cond Δ | S1 Δ | S2 Δ | rank_secondary |
|
||||
|---|---|---|---|---|---|---|---|---|---|
|
||||
| 1 | `v_shrink__b1__lam0.5` | 1.00 | 0.50 | | | 0.0267 | 0.0142 | 0.0391 | 0.0142 | 1 |
|
||||
| 2 | `v_cap__b1__c4` | 1.00 | | 4.0 | | 0.0064 | 0.0035 | 0.0035 | 0.0093 | 2 |
|
||||
| 3 | `v_cap__b1__c2` | 1.00 | | 2.0 | | -0.0024 | -0.0056 | -0.0056 | 0.0007 | 3 |
|
||||
| 4 | `v_logweight` | 0.00 | | | | -0.0139 | -0.0346 | 0.0067 | -0.0346 | 5 |
|
||||
| 5 | `v_minsup__t10` | 0.00 | | | 10 | -0.0302 | -0.0438 | -0.0166 | -0.0438 | 6 |
|
||||
| 6 | `v_beta__b1.5` | 1.50 | | | | -0.0485 | -0.0918 | -0.0918 | -0.0052 | 4 |
|
||||
|
||||
### 5.2 Confirmatory runs, per seed
|
||||
|
||||
| dataset | α | seed | config | val rare-F1 | test rare-F1 | Δval vs orig | Δtest vs orig | Δval vs β=1 | Δtest vs β=1 |
|
||||
|---|---|---|---|---|---|---|---|---|---|
|
||||
| xiiotid | 0.25 | 3 | `v_shrink__b1__lam0.5` | 0.6605 | 0.6611 | 0.0085 | 0.0094 | 0.0261 | 0.0241 |
|
||||
| xiiotid | 0.25 | 3 | `v_cap__b1__c4` | 0.6930 | 0.6929 | 0.0410 | 0.0413 | 0.0587 | 0.0559 |
|
||||
| xiiotid | 0.25 | 3 | `support_weighted__beta0.5` | 0.6695 | 0.6697 | 0.0175 | 0.0181 | 0.0352 | 0.0327 |
|
||||
| xiiotid | 0.25 | 3 | `support_weighted__beta1` | 0.6343 | 0.6370 | -0.0177 | -0.0146 | 0.0000 | 0.0000 |
|
||||
| xiiotid | 0.25 | 4 | `v_shrink__b1__lam0.5` | 0.7155 | 0.7164 | 0.0329 | 0.0332 | 0.1713 | 0.1745 |
|
||||
| xiiotid | 0.25 | 4 | `v_cap__b1__c4` | 0.6612 | 0.6628 | -0.0214 | -0.0204 | 0.1170 | 0.1209 |
|
||||
| xiiotid | 0.25 | 4 | `support_weighted__beta0.5` | 0.6745 | 0.6745 | -0.0082 | -0.0087 | 0.1302 | 0.1326 |
|
||||
| xiiotid | 0.25 | 4 | `support_weighted__beta1` | 0.5443 | 0.5419 | -0.1384 | -0.1413 | 0.0000 | 0.0000 |
|
||||
| 5gnidd | 0.50 | 3 | `v_shrink__b1__lam0.5` | 0.8314 | 0.8276 | 0.0269 | 0.0276 | -0.0888 | -0.0895 |
|
||||
| 5gnidd | 0.50 | 3 | `v_cap__b1__c4` | 0.8064 | 0.8044 | 0.0020 | 0.0044 | -0.1138 | -0.1128 |
|
||||
| 5gnidd | 0.50 | 3 | `support_weighted__beta0.5` | 0.8389 | 0.8370 | 0.0344 | 0.0370 | -0.0813 | -0.0801 |
|
||||
| 5gnidd | 0.50 | 3 | `support_weighted__beta1` | 0.9202 | 0.9172 | 0.1158 | 0.1172 | 0.0000 | 0.0000 |
|
||||
| 5gnidd | 0.50 | 4 | `v_shrink__b1__lam0.5` | 0.9297 | 0.9265 | 0.0038 | 0.0032 | 0.0285 | 0.0262 |
|
||||
| 5gnidd | 0.50 | 4 | `v_cap__b1__c4` | 0.9231 | 0.9216 | -0.0029 | -0.0017 | 0.0219 | 0.0213 |
|
||||
| 5gnidd | 0.50 | 4 | `support_weighted__beta0.5` | 0.9258 | 0.9255 | -0.0001 | 0.0023 | 0.0246 | 0.0253 |
|
||||
| 5gnidd | 0.50 | 4 | `support_weighted__beta1` | 0.9012 | 0.9002 | -0.0248 | -0.0231 | 0.0000 | 0.0000 |
|
||||
|
||||
### 5.3 Confirmatory summary
|
||||
|
||||
A variant “improves” under the pre-registered rule only if the mean validation difference over the four pairs is positive **and** all four are positive.
|
||||
|
||||
| variant | mean Δval vs orig | sd | positive/4 | mean Δtest vs orig | sd | mean Δval vs β=1 | mean Δtest vs β=1 | mean Δval vs current best | mean Δtest vs current best | improved |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| `v_shrink__b1__lam0.5` | 0.0180 | 0.0141 | 4/4 | 0.0184 | 0.0143 | 0.0343 | 0.0338 | -0.0153 | -0.0155 | True |
|
||||
| `v_cap__b1__c4` | 0.0047 | 0.0263 | 2/4 | 0.0059 | 0.0258 | 0.0210 | 0.0213 | -0.0286 | -0.0279 | False |
|
||||
|
||||
### 5.4 Reference configurations on the confirmation seeds
|
||||
|
||||
| config | mean Δval vs orig | sd | positive | mean Δtest vs orig | sd | positive |
|
||||
|---|---|---|---|---|---|---|
|
||||
| `support_weighted__beta0.5` | 0.0109 | 0.0190 | 2 | 0.0122 | 0.0199 | 3 |
|
||||
| `support_weighted__beta1` | -0.0163 | 0.1040 | 1 | -0.0155 | 0.1057 | 1 |
|
||||
|
||||
### 5.5 Reference consistency (environment check)
|
||||
|
||||
| condition | new original val | restored original val | sweep β=0 val | new − restored | new − sweep β=0 |
|
||||
|---|---|---|---|---|---|
|
||||
| S1 | 0.6380 | 0.6416 | 0.6433 | -0.0035 | -0.0052 |
|
||||
| S2 | 0.8615 | 0.8694 | 0.8677 | -0.0079 | -0.0061 |
|
||||
|
||||
### 5.6 Wall time and memory
|
||||
|
||||
| phase | run | status | wall h | peak GiB |
|
||||
|---|---|---|---|---|
|
||||
| screening | `xiiotid__alpha0.25__seed0__original_protean` | done | 3.02 | 8.38 |
|
||||
| screening | `5gnidd__alpha0.5__seed0__original_protean` | done | 4.67 | 10.30 |
|
||||
| screening | `xiiotid__alpha0.25__seed0__v_beta__b1.5` | done | 3.07 | 8.38 |
|
||||
| screening | `xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5` | done | 3.05 | 8.38 |
|
||||
| screening | `xiiotid__alpha0.25__seed0__v_cap__b1__c4` | done | 3.06 | 8.38 |
|
||||
| screening | `xiiotid__alpha0.25__seed0__v_cap__b1__c2` | done | 3.04 | 8.38 |
|
||||
| screening | `xiiotid__alpha0.25__seed0__v_minsup__t10` | done | 3.03 | 8.38 |
|
||||
| screening | `xiiotid__alpha0.25__seed0__v_logweight` | done | 2.96 | 8.38 |
|
||||
| screening | `5gnidd__alpha0.5__seed0__v_beta__b1.5` | done | 4.88 | 10.29 |
|
||||
| screening | `5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5` | done | 4.85 | 10.29 |
|
||||
| screening | `5gnidd__alpha0.5__seed0__v_cap__b1__c4` | done | 4.55 | 10.29 |
|
||||
| screening | `5gnidd__alpha0.5__seed0__v_cap__b1__c2` | done | 4.41 | 10.29 |
|
||||
| screening | `5gnidd__alpha0.5__seed0__v_minsup__t10` | done | 4.51 | 10.29 |
|
||||
| screening | `5gnidd__alpha0.5__seed0__v_logweight` | done | 4.82 | 10.31 |
|
||||
| confirm | `xiiotid__alpha0.25__seed3__original_protean` | done | 3.08 | 10.48 |
|
||||
| confirm | `xiiotid__alpha0.25__seed3__support_weighted__beta0.5` | done | 3.08 | 10.48 |
|
||||
| confirm | `xiiotid__alpha0.25__seed3__support_weighted__beta1` | done | 3.12 | 10.48 |
|
||||
| confirm | `xiiotid__alpha0.25__seed3__v_shrink__b1__lam0.5` | done | 2.97 | 10.48 |
|
||||
| confirm | `xiiotid__alpha0.25__seed3__v_cap__b1__c4` | done | 2.95 | 10.48 |
|
||||
| confirm | `xiiotid__alpha0.25__seed4__original_protean` | done | 3.11 | 12.75 |
|
||||
| confirm | `xiiotid__alpha0.25__seed4__support_weighted__beta0.5` | done | 3.10 | 12.76 |
|
||||
| confirm | `xiiotid__alpha0.25__seed4__support_weighted__beta1` | done | 3.20 | 12.76 |
|
||||
| confirm | `xiiotid__alpha0.25__seed4__v_shrink__b1__lam0.5` | done | 3.18 | 12.76 |
|
||||
| confirm | `xiiotid__alpha0.25__seed4__v_cap__b1__c4` | done | 2.82 | 12.76 |
|
||||
| confirm | `5gnidd__alpha0.5__seed3__original_protean` | done | 4.41 | 9.04 |
|
||||
| confirm | `5gnidd__alpha0.5__seed3__support_weighted__beta0.5` | done | 4.48 | 9.07 |
|
||||
| confirm | `5gnidd__alpha0.5__seed3__support_weighted__beta1` | done | 4.66 | 9.04 |
|
||||
| confirm | `5gnidd__alpha0.5__seed3__v_shrink__b1__lam0.5` | done | 4.57 | 9.06 |
|
||||
| confirm | `5gnidd__alpha0.5__seed3__v_cap__b1__c4` | done | 4.73 | 9.05 |
|
||||
| confirm | `5gnidd__alpha0.5__seed4__original_protean` | done | 4.81 | 11.12 |
|
||||
| confirm | `5gnidd__alpha0.5__seed4__support_weighted__beta0.5` | done | 4.77 | 11.16 |
|
||||
| confirm | `5gnidd__alpha0.5__seed4__support_weighted__beta1` | done | 4.88 | 11.13 |
|
||||
| confirm | `5gnidd__alpha0.5__seed4__v_shrink__b1__lam0.5` | done | 4.79 | 11.15 |
|
||||
| confirm | `5gnidd__alpha0.5__seed4__v_cap__b1__c4` | done | 4.56 | 11.14 |
|
||||
|
||||
### 5.7 Failed or missing runs
|
||||
|
||||
None.
|
||||
|
||||
<!-- AUTO_RESULTS_END -->
|
||||
|
||||
### 5.8 What the confirmation actually shows
|
||||
|
||||
**Screening (validation only, seed 0).** `v_shrink` (λ=0.5) ranked first
|
||||
(+0.0267 mean over S1/S2 vs the in-environment baseline) and `v_cap4` second
|
||||
(+0.0064), with a selection margin of 0.0203 between them. The remaining four
|
||||
candidates were at or below the baseline on the two-condition mean: `v_cap2` −0.0024,
|
||||
`v_logweight` −0.0139, `v_minsup` −0.0302, `v_beta1.5` −0.0485.
|
||||
|
||||
The same screening scores expressed against the current method's best β on each
|
||||
condition (β=0.75 for S1, +0.0310 vs baseline; β=1.00 for S2, +0.0147; mean
|
||||
+0.0229):
|
||||
|
||||
| variant | Δ vs original (mean) | Δ vs current-method best (mean) |
|
||||
|---|---|---|
|
||||
| `v_shrink` | +0.0267 | **+0.0038** |
|
||||
| `v_cap4` | +0.0064 | −0.0165 |
|
||||
| `v_cap2` | −0.0024 | −0.0253 |
|
||||
| `v_logweight` | −0.0139 | −0.0368 |
|
||||
| `v_minsup10` | −0.0302 | −0.0531 |
|
||||
| `v_beta1.5` | −0.0485 | −0.0714 |
|
||||
|
||||
Only `v_shrink` is above the current method's validation-selected best in this
|
||||
screening comparison, and by a small margin (+0.0038). The confirmation then
|
||||
shows that this small margin does not survive as a general advantage (§5.8).
|
||||
|
||||
**Top candidate, `v_shrink` (λ=0.5).** It meets the pre-registered improvement
|
||||
rule against the original baseline:
|
||||
|
||||
| statistic (4 confirmatory pairs) | validation | test |
|
||||
|---|---|---|
|
||||
| mean paired difference vs baseline | **+0.0180** | **+0.0184** |
|
||||
| sample sd of paired differences | 0.0141 | 0.0143 |
|
||||
| positive pairs | **4/4** | **4/4** |
|
||||
| X-IIoTID α=0.25, mean (seeds 3,4) | +0.0207 (+0.0085, +0.0329) | +0.0213 |
|
||||
| 5G-NIDD α=0.50, mean (seeds 3,4) | +0.0153 (+0.0269, +0.0038) | +0.0154 |
|
||||
|
||||
The direction is the same on every confirmatory seed and both conditions, and
|
||||
the test differences track the validation differences closely (mean
|
||||
validation−test = −0.0004). That is the strongest statement this design
|
||||
supports: a modest, direction-consistent gain over the **baseline** on the two
|
||||
new seeds.
|
||||
|
||||
**Second candidate, `v_cap4`.** It does **not** meet the rule: mean validation
|
||||
difference +0.0047, sd 0.0263, only **2/4** positive. The gain comes entirely
|
||||
from X-IIoTID seed 3 (+0.0410) and reverses on seed 4 (−0.0214); on 5G-NIDD it
|
||||
is +0.0020 / −0.0029. Mean test difference +0.0059 with the same mixed pattern.
|
||||
So the capping candidate is a negative/mixed result and remains in the tables.
|
||||
|
||||
**Versus the current proposed method.** Comparing each variant with the best
|
||||
validation score among {original, β=0.5, β=1} on the same pair:
|
||||
|
||||
- `v_shrink`: mean **−0.0153** (sd 0.0521, 2/4 pairs better). It improves on
|
||||
both seed-4 pairs (+0.0329 X-IIoTID, +0.0038 5G-NIDD) but loses on seed 3,
|
||||
mainly 5G-NIDD (−0.0888) where β=1 gains +0.1158 over the baseline.
|
||||
- `v_cap4`: mean **−0.0286** (sd 0.0597, 1/4 pairs better).
|
||||
|
||||
So `v_shrink` is **more stable than the current method but does not dominate
|
||||
it**. The current method's β=1 has a much higher peak on 5G-NIDD seed 3 and a
|
||||
much deeper failure on X-IIoTID seed 4 (−0.1384). This is a measured trade-off,
|
||||
not a win for either method.
|
||||
|
||||
**Reference behaviour on the new seeds.** β=0.5 has mean validation +0.0109
|
||||
(sd 0.0190, 2/4 positive) and test +0.0122 (3/4). β=1 has mean validation
|
||||
−0.0163 (sd 0.1040, 1/4 positive) and test −0.0155 (1/4): X-IIoTID −0.0780
|
||||
(−0.0177, −0.1384), 5G-NIDD +0.0455 (+0.1158, −0.0248). The large β=1 spread is
|
||||
the clearest measured instance of the seed sensitivity already visible in the
|
||||
old grid.
|
||||
|
||||
**No significance claim.** Four paired observations (two conditions × two
|
||||
seeds), no inferential test, and the sample standard deviations are of the same
|
||||
order as the means for most statistics. `v_shrink` passing the pre-registered
|
||||
rule means “positive on these four pairs”, not “superior in general”.
|
||||
|
||||
### 5.9 Where the `v_shrink` gain comes from (descriptive)
|
||||
|
||||
Condition-level means hide heterogeneity. Pooling the two confirmation seeds
|
||||
per dataset, test-F1 class deltas for `v_shrink` versus the original:
|
||||
|
||||
| dataset | largest gains | losses |
|
||||
|---|---|---|
|
||||
| X-IIoTID α=0.25 | C&C +0.072, Weaponization +0.061, Tampering +0.054 | Exploitation −0.010, Exfiltration −0.003, Lateral −0.002 |
|
||||
| 5G-NIDD α=0.50 | ICMPFlood +0.069 (seed 3 +0.143, seed 4 −0.004), SlowrateDoS +0.026, HTTPFlood +0.013 | SYNFlood −0.014 (both seeds) |
|
||||
|
||||
Per-client validation (10 clients × 2 seeds per dataset): X-IIoTID mean +0.0295
|
||||
but only **9 improve / 11 degrade**; 5G-NIDD mean +0.0119 with **12 improve /
|
||||
4 degrade**. So the positive condition-level result is not “every client wins”:
|
||||
on X-IIoTID the mean is pulled up by a few large attack-class/client gains while
|
||||
the majority of client-seed pairs lose a little.
|
||||
|
||||
The same view explains the other results:
|
||||
|
||||
- `v_cap4` on X-IIoTID gains Tampering +0.157 but loses **Normal −0.234**
|
||||
(seed 4 −0.475) and C&C −0.123; client pairs are 8 improve / 12 degrade. That
|
||||
is why its average is mixed and flips sign between seeds.
|
||||
- β=1 on X-IIoTID loses Tampering −0.366 and Normal −0.245; client pairs are
|
||||
3 improve / 17 degrade. On 5G-NIDD it gains ICMPFlood +0.200 and 11/5 client
|
||||
pairs improve, but seed 4 reverses the aggregate. This is the microscale
|
||||
origin of the large β=1 seed variance.
|
||||
|
||||
Full rows: `analysis/confirm_per_class_variant.csv` and
|
||||
`analysis/confirm_per_client_variant.csv`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Negative results, operational deviations and honesty notes
|
||||
|
||||
### 6.1 Negative and mixed results (measured)
|
||||
|
||||
- **`v_cap4` did not improve** under the pre-registered rule: mean validation
|
||||
+0.0047, sd 0.0263, 2/4 positive; the gain is seed-3 only (+0.0410 on
|
||||
X-IIoTID, −0.0214 on seed 4). It stays in the tables as a mixed/negative
|
||||
result.
|
||||
- **Expected-negative controls behaved as expected but not identically.**
|
||||
`v_minsup10` was worst on screening (−0.0302; S1 −0.0166, S2 −0.0438),
|
||||
consistent with removing low-support rare-class evidence. `v_cap2` was near
|
||||
zero (−0.0024). `v_logweight` was mixed (+0.0067 S1, −0.0346 S2) and overall
|
||||
negative. `v_beta1.5` was the worst (−0.0485; S1 −0.0918), confirming that
|
||||
extending β beyond 1 concentrates weight in the wrong direction at α=0.25.
|
||||
- **The current method's β=1 is strongly seed-dependent** on the new seeds:
|
||||
mean validation −0.0163, sd 0.1040, 1/4 positive. It ranges from +0.1158
|
||||
(5G-NIDD seed 3) to −0.1384 (X-IIoTID seed 4). β=0.5 is more stable
|
||||
(+0.0109, sd 0.0190) but weaker.
|
||||
- **The analysis-level selection-metric candidate (C7) was not confirmed.**
|
||||
Its exploratory gain (+0.0082 vs +0.0052 mean test difference on the old
|
||||
grid) uses the burned seeds and is not part of the new confirmation. It
|
||||
remains a hypothesis for future work.
|
||||
- **No variant was tested at α=0.75.** The confirmation conditions were fixed
|
||||
to α=0.25 (X-IIoTID) and α=0.50 (5G-NIDD); the report does not extrapolate.
|
||||
|
||||
### 6.2 Operational deviations (with timestamps)
|
||||
|
||||
The ranking was frozen at 2026-10-31T05:03:55Z before any confirmatory run, and
|
||||
was never recomputed. The following operational events are recorded because they
|
||||
changed execution, not the scientific design:
|
||||
|
||||
| when (UTC) | id | event | action |
|
||||
|---|---|---|---|
|
||||
| 2026-10-30T04:10Z | A1 | wrapper resolved repo root one level too high; six attempts exited 127 before Python started | path fixed; attempts archived; no science |
|
||||
| 2026-10-30T04:32Z | A2 | restored grid came from another host; environment difference measured at median 0.0022 / max 0.0127 test rare-F1 | +2 in-environment baseline runs; 34 runs total |
|
||||
| 2026-10-31T08:35Z | A3 | two seed-4 reference runs OOM-killed twice at 11 GiB | requeued, `max_procs` 3→2, OOM→137 mapping |
|
||||
| 2026-10-31T09:50Z | A4 | three OOM kills total; user asked to prevent further OOM | X-IIoTID cap 11→13 GiB, `max_procs=2`, host `MemAvailable ≥ 12 GiB` guard |
|
||||
| 2026-10-31T14:12Z | A5 | retries blocked by stale systemd unit names, misread as OOM | `reset-failed` before launch; failed-start guard |
|
||||
| 2026-10-31T09:41/11:08Z | A6 | editing `run_one_v2.sh` while two wrappers were running caused exit 127 after training finished | both retried; archived first attempts are bit-identical to the final runs |
|
||||
| 2026-10-31T22:35Z | — | driver wrote `DONE` `status=complete` | 34/34 done, 0 terminal failures, 66.4 h |
|
||||
|
||||
The A6 retries are a free reproducibility check: for both affected seed-3
|
||||
variants, the archived first attempt and the final run have identical
|
||||
`val_global_metrics.json`, `test_global_metrics.json`, `val_selection.json` and
|
||||
a byte-identical round-0 snapshot. The retry did not change any result.
|
||||
|
||||
A partial `DONE` (`status=stopped`) was produced at 2026-10-31T14:07Z during the
|
||||
A5 incident; it was archived to `logs/DONE.partial_20261031T1412Z` and the run
|
||||
resumed. The final `DONE` is `complete`. All failed attempts are kept under
|
||||
`results/attempts/` and the pre-campaign bug attempts under
|
||||
`results/_driver_bug_20261030T0410Z/`.
|
||||
|
||||
### 6.3 Honesty notes
|
||||
|
||||
- Screening six variants raises the chance that the top one is lucky; the
|
||||
confirmation on seeds never used in any analysis exists for that reason.
|
||||
- No test metric of any new run was read before the ranking was frozen. The
|
||||
ranking code opened only `val_*` files (see `ACCESS_LOG.txt`); the
|
||||
post-freeze analysis read test metrics only after `ranking.sha256` existed.
|
||||
- No significance test is performed and no superiority is claimed.
|
||||
- A modification that did not improve is reported as such (`v_cap4`, and the
|
||||
four candidates that never reached confirmation).
|
||||
|
||||
## 7. Limitations
|
||||
|
||||
1. Two datasets, two conditions, ten clients, one architecture and one training
|
||||
configuration; only α=0.25 (X-IIoTID) and α=0.50 (5G-NIDD) reached
|
||||
confirmation.
|
||||
2. Confirmation has **four paired observations** (two conditions × two seeds).
|
||||
The sample standard deviations are of the same order as the means; no
|
||||
inferential test and no generalization claim.
|
||||
3. The `S_j` participant rule remains a reproduction assumption; all results are
|
||||
conditional on it.
|
||||
4. The paper comparison is limited by the reproduction gap in §2.8.
|
||||
5. Host/library differences between the restored grid and this environment are
|
||||
why A2 added in-environment baselines. Residual environment effects for the
|
||||
β-grid reference (taken from the 1-thread sweep) cannot be excluded.
|
||||
6. The confirmation β-grid reference is truncated to β=0.5, β=1.0 and the
|
||||
original (a β=0 proxy); the full five-point grid was not run on the new
|
||||
seeds, for budget reasons stated before any confirmation run.
|
||||
7. X-IIoTID seed-4 confirmation runs peaked at **12.76 GiB**, above the old
|
||||
11 GiB cap and close to the final 13 GiB cap. The results are conditional on
|
||||
the 13 GiB cap; a smaller cap would have killed them.
|
||||
8. Rare-class support differs across seeds, so absolute metric levels are not
|
||||
comparable across seeds; only paired differences are used.
|
||||
9. The “current best” comparison uses the per-pair best of
|
||||
{original, β=0.5, β=1} on validation. It is a fair proxy for the deployed
|
||||
method on these seeds, but it is not the pooled-across-seeds selection used
|
||||
in the original thesis protocol.
|
||||
|
||||
## 8. What the evidence supports and what it does not
|
||||
|
||||
**Supports (measured):**
|
||||
|
||||
- `v_shrink` (β=1, λ=0.5, half-way between equal and support-weighted) improved
|
||||
over the **original baseline** on validation in 4/4 confirmation pairs:
|
||||
mean +0.0180 (sd 0.0141), with test differences of the same size and
|
||||
direction (mean +0.0184, 4/4). This is a modest, direction-consistent gain on
|
||||
two unseen seeds, not a large one.
|
||||
- `v_cap4` did **not** improve (2/4, mean +0.0047): capping at 4×median is not
|
||||
enough, or is the wrong shape, on these conditions.
|
||||
- The current method's β=1 is highly seed-sensitive (sd 0.1040 across the four
|
||||
pairs, 1/4 positive); β=0.5 is more stable but weaker.
|
||||
- From Phase 2: support weighting can lose substantially at high
|
||||
heterogeneity; the loss is class- and client-specific; the deployed
|
||||
per-client selection metric can disagree with the global headline metric;
|
||||
displacement is not a detection-quality proxy.
|
||||
|
||||
**Does not support:**
|
||||
|
||||
- Any claim that `v_shrink` is better than the current proposed method. Against
|
||||
the per-pair best of {original, β=0.5, β=1} it is **−0.0153** on validation
|
||||
(2/4 pairs better), mainly because β=1 gains +0.1158 on 5G-NIDD seed 3.
|
||||
- Any claim of statistical significance, superiority, or generalisation beyond
|
||||
these two datasets, two conditions and two new seeds.
|
||||
- Any universal or globally optimal β, or any causal α→β rule.
|
||||
- Any causal link from prototype displacement to detection performance.
|
||||
- Any statement that support weighting always helps or always hurts.
|
||||
|
||||
**Unknown:**
|
||||
|
||||
- Why β=1 is so seed-sensitive on 5G-NIDD seed 3 versus X-IIoTID seed 4.
|
||||
- Whether a pooled-across-seeds selection would change the current-method
|
||||
comparison.
|
||||
- Whether `v_shrink` helps at α=0.75 or on other datasets; not tested.
|
||||
- Whether the C7 selection-metric change would survive new seeds; not
|
||||
confirmed.
|
||||
@@ -0,0 +1,102 @@
|
||||
# exploration_v2 — report data
|
||||
Generated: 2026-11-02T03:36:03Z
|
||||
This file is generated by `exploration_v2/scripts/analyze_results.py`. All numbers come from files on disk. Missing rows mean a run did not produce the metric.
|
||||
## Plan and ranking freeze
|
||||
| item | value |
|
||||
|---|---|
|
||||
| `PLAN.sha256` | `2118f31b30270e1d806cf7acdac2249da625646f2d9ce3a0cee96307317c978e PLAN.md` at 2026-10-30T04:07:47Z |
|
||||
| `ranking.sha256` | `f43ebc762d1512c5decfda51f31bef7f1d089a13156e8e3c3d7eae2982b054d3 ranking.json` at 2026-10-31T05:03:55Z |
|
||||
|
||||
## Screening ranking (validation only)
|
||||
Top-1 minus top-2 validation score (selection margin): 0.020278 (top2 = ['v_shrink__b1__lam0.5', 'v_cap__b1__c4']).
|
||||
|
||||
Score = mean over S1,S2 of the paired validation difference in global rare-class macro-F1 versus the original baseline.
|
||||
|
||||
| rank | variant | β | λ | cap | min N | score | min cond Δ | S1 Δ | S2 Δ | secondary rank |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| 1 | `v_shrink__b1__lam0.5` | 1.00 | 0.50 | | | 0.0267 | 0.0142 | 0.0391 | 0.0142 | 1 |
|
||||
| 2 | `v_cap__b1__c4` | 1.00 | | 4.0 | | 0.0064 | 0.0035 | 0.0035 | 0.0093 | 2 |
|
||||
| 3 | `v_cap__b1__c2` | 1.00 | | 2.0 | | -0.0024 | -0.0056 | -0.0056 | 0.0007 | 3 |
|
||||
| 4 | `v_logweight` | 0.00 | | | | -0.0139 | -0.0346 | 0.0067 | -0.0346 | 5 |
|
||||
| 5 | `v_minsup__t10` | 0.00 | | | 10 | -0.0302 | -0.0438 | -0.0166 | -0.0438 | 6 |
|
||||
| 6 | `v_beta__b1.5` | 1.50 | | | | -0.0485 | -0.0918 | -0.0918 | -0.0052 | 4 |
|
||||
|
||||
## Confirmatory results (per seed)
|
||||
| dataset | α | seed | config | val rare-F1 | test rare-F1 | Δval vs orig | Δtest vs orig | Δval vs β=1 | Δtest vs β=1 |
|
||||
|---|---|---|---|---|---|---|---|---|---|
|
||||
| xiiotid | 0.25 | 3 | `v_shrink__b1__lam0.5` | 0.6605 | 0.6611 | 0.0085 | 0.0094 | 0.0261 | 0.0241 |
|
||||
| xiiotid | 0.25 | 3 | `v_cap__b1__c4` | 0.6930 | 0.6929 | 0.0410 | 0.0413 | 0.0587 | 0.0559 |
|
||||
| xiiotid | 0.25 | 3 | `support_weighted__beta0.5` | 0.6695 | 0.6697 | 0.0175 | 0.0181 | 0.0352 | 0.0327 |
|
||||
| xiiotid | 0.25 | 3 | `support_weighted__beta1` | 0.6343 | 0.6370 | -0.0177 | -0.0146 | 0.0000 | 0.0000 |
|
||||
| xiiotid | 0.25 | 4 | `v_shrink__b1__lam0.5` | 0.7155 | 0.7164 | 0.0329 | 0.0332 | 0.1713 | 0.1745 |
|
||||
| xiiotid | 0.25 | 4 | `v_cap__b1__c4` | 0.6612 | 0.6628 | -0.0214 | -0.0204 | 0.1170 | 0.1209 |
|
||||
| xiiotid | 0.25 | 4 | `support_weighted__beta0.5` | 0.6745 | 0.6745 | -0.0082 | -0.0087 | 0.1302 | 0.1326 |
|
||||
| xiiotid | 0.25 | 4 | `support_weighted__beta1` | 0.5443 | 0.5419 | -0.1384 | -0.1413 | 0.0000 | 0.0000 |
|
||||
| 5gnidd | 0.50 | 3 | `v_shrink__b1__lam0.5` | 0.8314 | 0.8276 | 0.0269 | 0.0276 | -0.0888 | -0.0895 |
|
||||
| 5gnidd | 0.50 | 3 | `v_cap__b1__c4` | 0.8064 | 0.8044 | 0.0020 | 0.0044 | -0.1138 | -0.1128 |
|
||||
| 5gnidd | 0.50 | 3 | `support_weighted__beta0.5` | 0.8389 | 0.8370 | 0.0344 | 0.0370 | -0.0813 | -0.0801 |
|
||||
| 5gnidd | 0.50 | 3 | `support_weighted__beta1` | 0.9202 | 0.9172 | 0.1158 | 0.1172 | 0.0000 | 0.0000 |
|
||||
| 5gnidd | 0.50 | 4 | `v_shrink__b1__lam0.5` | 0.9297 | 0.9265 | 0.0038 | 0.0032 | 0.0285 | 0.0262 |
|
||||
| 5gnidd | 0.50 | 4 | `v_cap__b1__c4` | 0.9231 | 0.9216 | -0.0029 | -0.0017 | 0.0219 | 0.0213 |
|
||||
| 5gnidd | 0.50 | 4 | `support_weighted__beta0.5` | 0.9258 | 0.9255 | -0.0001 | 0.0023 | 0.0246 | 0.0253 |
|
||||
| 5gnidd | 0.50 | 4 | `support_weighted__beta1` | 0.9012 | 0.9002 | -0.0248 | -0.0231 | 0.0000 | 0.0000 |
|
||||
|
||||
## Confirmatory summary
|
||||
| variant | mean Δval vs orig | sd | positive/4 | mean Δtest vs orig | sd | mean Δval vs β=1 | mean Δtest vs β=1 | mean Δval vs current best | mean Δtest vs current best | improved per plan |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| `v_shrink__b1__lam0.5` | 0.0180 | 0.0141 | 4/4 | 0.0184 | 0.0143 | 0.0343 | 0.0338 | -0.0153 | -0.0155 | True |
|
||||
| `v_cap__b1__c4` | 0.0047 | 0.0263 | 2/4 | 0.0059 | 0.0258 | 0.0210 | 0.0213 | -0.0286 | -0.0279 | False |
|
||||
|
||||
## Reference configurations on the confirmation seeds
|
||||
| config | mean Δval vs orig | sd | positive | mean Δtest vs orig | sd | positive |
|
||||
|---|---|---|---|---|---|---|
|
||||
| `support_weighted__beta0.5` | 0.0109 | 0.0190 | 2 | 0.0122 | 0.0199 | 3 |
|
||||
| `support_weighted__beta1` | -0.0163 | 0.1040 | 1 | -0.0155 | 0.1057 | 1 |
|
||||
|
||||
## Reference consistency (environment check)
|
||||
| condition | new original val | restored original val | sweep β=0 val | new − restored | new − sweep β=0 |
|
||||
|---|---|---|---|---|---|
|
||||
| S1 | 0.6380 | 0.6416 | 0.6433 | -0.0035 | -0.0052 |
|
||||
| S2 | 0.8615 | 0.8694 | 0.8677 | -0.0079 | -0.0061 |
|
||||
|
||||
## Wall time and memory (new runs)
|
||||
| phase | run | status | wall h | peak GiB |
|
||||
|---|---|---|---|---|
|
||||
| screening | `xiiotid__alpha0.25__seed0__original_protean` | done | 3.02 | 8.38 |
|
||||
| screening | `5gnidd__alpha0.5__seed0__original_protean` | done | 4.67 | 10.30 |
|
||||
| screening | `xiiotid__alpha0.25__seed0__v_beta__b1.5` | done | 3.07 | 8.38 |
|
||||
| screening | `xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5` | done | 3.05 | 8.38 |
|
||||
| screening | `xiiotid__alpha0.25__seed0__v_cap__b1__c4` | done | 3.06 | 8.38 |
|
||||
| screening | `xiiotid__alpha0.25__seed0__v_cap__b1__c2` | done | 3.04 | 8.38 |
|
||||
| screening | `xiiotid__alpha0.25__seed0__v_minsup__t10` | done | 3.03 | 8.38 |
|
||||
| screening | `xiiotid__alpha0.25__seed0__v_logweight` | done | 2.96 | 8.38 |
|
||||
| screening | `5gnidd__alpha0.5__seed0__v_beta__b1.5` | done | 4.88 | 10.29 |
|
||||
| screening | `5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5` | done | 4.85 | 10.29 |
|
||||
| screening | `5gnidd__alpha0.5__seed0__v_cap__b1__c4` | done | 4.55 | 10.29 |
|
||||
| screening | `5gnidd__alpha0.5__seed0__v_cap__b1__c2` | done | 4.41 | 10.29 |
|
||||
| screening | `5gnidd__alpha0.5__seed0__v_minsup__t10` | done | 4.51 | 10.29 |
|
||||
| screening | `5gnidd__alpha0.5__seed0__v_logweight` | done | 4.82 | 10.31 |
|
||||
| confirm | `xiiotid__alpha0.25__seed3__original_protean` | done | 3.08 | 10.48 |
|
||||
| confirm | `xiiotid__alpha0.25__seed3__support_weighted__beta0.5` | done | 3.08 | 10.48 |
|
||||
| confirm | `xiiotid__alpha0.25__seed3__support_weighted__beta1` | done | 3.12 | 10.48 |
|
||||
| confirm | `xiiotid__alpha0.25__seed3__v_shrink__b1__lam0.5` | done | 2.97 | 10.48 |
|
||||
| confirm | `xiiotid__alpha0.25__seed3__v_cap__b1__c4` | done | 2.95 | 10.48 |
|
||||
| confirm | `xiiotid__alpha0.25__seed4__original_protean` | done | 3.11 | 12.75 |
|
||||
| confirm | `xiiotid__alpha0.25__seed4__support_weighted__beta0.5` | done | 3.10 | 12.76 |
|
||||
| confirm | `xiiotid__alpha0.25__seed4__support_weighted__beta1` | done | 3.20 | 12.76 |
|
||||
| confirm | `xiiotid__alpha0.25__seed4__v_shrink__b1__lam0.5` | done | 3.18 | 12.76 |
|
||||
| confirm | `xiiotid__alpha0.25__seed4__v_cap__b1__c4` | done | 2.82 | 12.76 |
|
||||
| confirm | `5gnidd__alpha0.5__seed3__original_protean` | done | 4.41 | 9.04 |
|
||||
| confirm | `5gnidd__alpha0.5__seed3__support_weighted__beta0.5` | done | 4.48 | 9.07 |
|
||||
| confirm | `5gnidd__alpha0.5__seed3__support_weighted__beta1` | done | 4.66 | 9.04 |
|
||||
| confirm | `5gnidd__alpha0.5__seed3__v_shrink__b1__lam0.5` | done | 4.57 | 9.06 |
|
||||
| confirm | `5gnidd__alpha0.5__seed3__v_cap__b1__c4` | done | 4.73 | 9.05 |
|
||||
| confirm | `5gnidd__alpha0.5__seed4__original_protean` | done | 4.81 | 11.12 |
|
||||
| confirm | `5gnidd__alpha0.5__seed4__support_weighted__beta0.5` | done | 4.77 | 11.16 |
|
||||
| confirm | `5gnidd__alpha0.5__seed4__support_weighted__beta1` | done | 4.88 | 11.13 |
|
||||
| confirm | `5gnidd__alpha0.5__seed4__v_shrink__b1__lam0.5` | done | 4.79 | 11.15 |
|
||||
| confirm | `5gnidd__alpha0.5__seed4__v_cap__b1__c4` | done | 4.56 | 11.14 |
|
||||
|
||||
## Failed or missing runs
|
||||
None.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# exploration_v2 setup check
|
||||
|
||||
Generated: 2026-11-02T03:38:12.876063Z
|
||||
|
||||
| check | result | detail |
|
||||
|---|---|---|
|
||||
| plan_hash_matches | PASS | 2118f31b30270e1d806cf7acdac2249da625646f2d9ce3a0cee96307317c978e |
|
||||
| no_tracked_modifications | PASS | |
|
||||
| planningawal_unchanged | PASS | |
|
||||
| no_raw_dataset_in_repo | PASS | |
|
||||
| original_tests_pass | PASS | ... [100%] |
|
||||
| variant_tests_pass | PASS | .............. [100%] |
|
||||
| confirm_seeds_new | PASS | restored seeds=[0, 1, 2] |
|
||||
| manifest_ok_5gnidd__alpha0.5__seed4.json | PASS | seed=4 |
|
||||
| manifest_ok_xiiotid__alpha0.25__seed4.json | PASS | seed=4 |
|
||||
| manifest_ok_xiiotid__alpha0.25__seed3.json | PASS | seed=3 |
|
||||
| manifest_ok_5gnidd__alpha0.5__seed3.json | PASS | seed=3 |
|
||||
|
||||
Overall: PASS
|
||||
@@ -0,0 +1,55 @@
|
||||
# Final status — exploration_v2
|
||||
|
||||
UTC: 2026-11-02T03:36Z
|
||||
Repository: `/home/willtanoe/project/prototype-agregation`
|
||||
|
||||
## Outcome
|
||||
|
||||
- Driver finished 2026-11-01T22:35:36Z; `DONE` says `status=complete`.
|
||||
- **34/34 scientific runs done**, 0 terminal failures.
|
||||
- Wall time: **66.4 h** of the 96 h budget.
|
||||
- Screening: 14 runs (12 variants + 2 in-environment baselines).
|
||||
- Confirmation: 20 runs (top-2 variants + original + β=0.5 + β=1 on seeds 3
|
||||
and 4, two conditions).
|
||||
- Frozen plan hash: `2118f31b30270e1d806cf7acdac2249da625646f2d9ce3a0cee96307317c978e`.
|
||||
- Frozen ranking hash: `f43ebc762d1512c5decfda51f31bef7f1d089a13156e8e3c3d7eae2982b054d3`.
|
||||
|
||||
## Headline result
|
||||
|
||||
- `v_shrink` (β=1, λ=0.5) improved over the original baseline on validation in
|
||||
**4/4** confirmation pairs: mean **+0.0180** (sd 0.0141); test mean +0.0184
|
||||
(4/4). It therefore meets the pre-registered improvement rule.
|
||||
- `v_cap4` did **not**: mean +0.0047, 2/4.
|
||||
- Neither beats the current method's per-pair best
|
||||
{original, β=0.5, β=1}: `v_shrink` mean **−0.0153** on validation (2/4 pairs
|
||||
better), mainly because β=1 gains +0.1158 on 5G-NIDD seed 3.
|
||||
- β=1 was highly seed-sensitive (mean −0.0163, sd 0.1040, 1/4 positive).
|
||||
|
||||
## Files
|
||||
|
||||
- `REPORT.md` — complete narrative (Phase 1, Phase 2, design, results,
|
||||
negative results, deviations, limitations, support/does-not-support).
|
||||
- `REPORT_DATA.md`, `analysis/*.csv` — all numeric tables.
|
||||
- `PHASE12_ANALYSIS.md`, `CANDIDATES.md`, `PLAN.md`, `PLAN_CHECK.md`,
|
||||
`PLAN_AMENDMENTS.md` (A1–A5), `ISSUES.md`, `HANDOFF.md`.
|
||||
- `results/runs/` (34 COMPLETE), `results/attempts/` (archived failures),
|
||||
`results/_driver_bug_20261030T0410Z/` (pre-campaign path bug).
|
||||
- `ranking.json` / `ranking.sha256`, `ACCESS_LOG.txt` (52 validation-only
|
||||
opens; zero test/per-client/history opens).
|
||||
|
||||
## Integrity
|
||||
|
||||
- No tracked file modified; `git diff --stat` empty; `planningawal/` unchanged.
|
||||
- No raw dataset copied into the repository.
|
||||
- No commit or push performed.
|
||||
- No statistical significance or superiority claim is made.
|
||||
|
||||
## Open issues / limitations
|
||||
|
||||
- Four confirmatory pairs only; no inferential test.
|
||||
- Confirmation conditions limited to X-IIoTID α=0.25 and 5G-NIDD α=0.50.
|
||||
- X-IIoTID seed-4 runs peaked at 12.76 GiB, close to the 13 GiB cap adopted
|
||||
after the OOM incident.
|
||||
- The current-method reference on new seeds is truncated to β=0.5, β=1 and the
|
||||
original (β=0 proxy).
|
||||
- C7 (global selection metric) remains exploratory on burned seeds.
|
||||
@@ -0,0 +1,17 @@
|
||||
dataset,alpha,seed,config,run_id,val_global_rare_f1,val_per_client_rare_f1,test_rare_f1,test_rare_recall,baseline_val_global,baseline_test_rare_f1,delta_val_vs_original,delta_test_vs_original,delta_val_vs_beta1,delta_test_vs_beta1,delta_val_vs_beta05,delta_test_vs_beta05,current_best_config,current_best_val_global,delta_val_vs_current_best,delta_test_vs_current_best
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,xiiotid__alpha0.25__seed3__v_shrink__b1__lam0.5,0.6604599138123004,0.6835769827947561,0.6611166614366842,0.834631327602874,0.6520038277014277,0.6516753883176936,0.008456086110872674,0.009441273118990678,0.026139916018731668,0.024068007268394864,-0.009056466053729562,-0.008628509118876138,support_weighted__beta0.5,0.66951637986603,-0.009056466053729562,-0.008628509118876138
|
||||
xiiotid,0.25,3,v_cap__b1__c4,xiiotid__alpha0.25__seed3__v_cap__b1__c4,0.6930347111029873,0.6974933387696897,0.6929355556853871,0.8169158784862602,0.6520038277014277,0.6516753883176936,0.04103088340155958,0.041260167367693557,0.058714713309418576,0.05588690151709774,0.023518331236957346,0.02319038512982674,support_weighted__beta0.5,0.66951637986603,0.023518331236957346,0.02319038512982674
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,xiiotid__alpha0.25__seed3__support_weighted__beta0.5,0.66951637986603,0.6806478241186118,0.6697451705555604,0.8147471250008732,0.6520038277014277,0.6516753883176936,0.017512552164602235,0.018069782237866816,0.03519638207246123,0.032696516387271,0.0,0.0,support_weighted__beta0.5,0.66951637986603,0.0,0.0
|
||||
xiiotid,0.25,3,support_weighted__beta1,xiiotid__alpha0.25__seed3__support_weighted__beta1,0.6343199977935687,0.6443454840057614,0.6370486541682894,0.7953041343152203,0.6520038277014277,0.6516753883176936,-0.017683829907858994,-0.014626734149404186,0.0,0.0,-0.03519638207246123,-0.032696516387271,support_weighted__beta0.5,0.66951637986603,-0.03519638207246123,-0.032696516387271
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,xiiotid__alpha0.25__seed4__v_shrink__b1__lam0.5,0.7155211309912932,0.5875322150240144,0.7163859069449825,0.8549205204777552,0.6826579058578224,0.6832331434606697,0.03286322513347084,0.03315276348431284,0.17126530669398643,0.17449076882237846,0.04105079335795048,0.04186336031153037,original_protean,0.6826579058578224,0.03286322513347084,0.03315276348431284
|
||||
xiiotid,0.25,4,v_cap__b1__c4,xiiotid__alpha0.25__seed4__v_cap__b1__c4,0.6612274834490823,0.5895548490218416,0.662809680890142,0.8345629884018604,0.6826579058578224,0.6832331434606697,-0.021430422408740046,-0.02042346257052763,0.11697165915177554,0.12091454276753799,-0.01324285418426041,-0.011712865743310097,original_protean,0.6826579058578224,-0.021430422408740046,-0.02042346257052763
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,xiiotid__alpha0.25__seed4__support_weighted__beta0.5,0.6744703376333427,0.5946075229514161,0.6745225466334521,0.8293580156927381,0.6826579058578224,0.6832331434606697,-0.008187568224479636,-0.008710596827217532,0.13021451333603595,0.1326274085108481,0.0,0.0,original_protean,0.6826579058578224,-0.008187568224479636,-0.008710596827217532
|
||||
xiiotid,0.25,4,support_weighted__beta1,xiiotid__alpha0.25__seed4__support_weighted__beta1,0.5442558242973068,0.42910855853255436,0.541895138122604,0.6966345934869704,0.6826579058578224,0.6832331434606697,-0.1384020815605156,-0.14133800533806562,0.0,0.0,-0.13021451333603595,-0.1326274085108481,original_protean,0.6826579058578224,-0.1384020815605156,-0.14133800533806562
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,5gnidd__alpha0.5__seed3__v_shrink__b1__lam0.5,0.831360062139045,0.8667377269112777,0.8276438788886984,0.9892275573304957,0.8044578347431527,0.7999980487126149,0.02690222739589232,0.027645830176083463,-0.08884958289572842,-0.08952434009919907,-0.007525129739533343,-0.009401964142520147,support_weighted__beta1,0.9202096450347734,-0.08884958289572842,-0.08952434009919907
|
||||
5gnidd,0.5,3,v_cap__b1__c4,5gnidd__alpha0.5__seed3__v_cap__b1__c4,0.8064198040760951,0.8437023476357212,0.8043697046783258,0.9921040309667984,0.8044578347431527,0.7999980487126149,0.0019619693329424592,0.0043716559657108744,-0.11378984095867828,-0.11279851430957166,-0.0324653878024832,-0.032676138352892736,support_weighted__beta1,0.9202096450347734,-0.11378984095867828,-0.11279851430957166
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,5gnidd__alpha0.5__seed3__support_weighted__beta0.5,0.8388851918785784,0.8727486080528835,0.8370458430312185,0.9909209257334471,0.8044578347431527,0.7999980487126149,0.03442735713542566,0.03704779431860361,-0.08132445315619508,-0.08012237595667893,0.0,0.0,support_weighted__beta1,0.9202096450347734,-0.08132445315619508,-0.08012237595667893
|
||||
5gnidd,0.5,3,support_weighted__beta1,5gnidd__alpha0.5__seed3__support_weighted__beta1,0.9202096450347734,0.9429509748552004,0.9171682189878975,0.9866951889574849,0.8044578347431527,0.7999980487126149,0.11575181029162074,0.11717017027528254,0.0,0.0,0.08132445315619508,0.08012237595667893,support_weighted__beta1,0.9202096450347734,0.0,0.0
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,5gnidd__alpha0.5__seed4__v_shrink__b1__lam0.5,0.9296850930111598,0.8880565443840929,0.9264737095074091,0.9657604065424229,0.9259273982940985,0.9232963015030996,0.003757694717061222,0.0031774080043095454,0.028523543149283515,0.026239840648658586,0.0038793926743494467,0.0009244400791833529,original_protean,0.9259273982940985,0.003757694717061222,0.0031774080043095454
|
||||
5gnidd,0.5,4,v_cap__b1__c4,5gnidd__alpha0.5__seed4__v_cap__b1__c4,0.9230772912397688,0.884532344077232,0.9215621117759981,0.967188414469838,0.9259273982940985,0.9232963015030996,-0.0028501070543297535,-0.0017341897271014872,0.02191574137789254,0.021328242917247553,-0.0027284090970415287,-0.00398715765222768,original_protean,0.9259273982940985,-0.0028501070543297535,-0.0017341897271014872
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,5gnidd__alpha0.5__seed4__support_weighted__beta0.5,0.9258057003368103,0.88601978325071,0.9255492694282258,0.9668784318423409,0.9259273982940985,0.9232963015030996,-0.00012169795728822486,0.0022529679251261925,0.024644150474934068,0.025315400569475233,0.0,0.0,original_protean,0.9259273982940985,-0.00012169795728822486,0.0022529679251261925
|
||||
5gnidd,0.5,4,support_weighted__beta1,5gnidd__alpha0.5__seed4__support_weighted__beta1,0.9011615498618762,0.8562921340984854,0.9002338688587506,0.9672615025827914,0.9259273982940985,0.9232963015030996,-0.024765848432222293,-0.02306243264434904,0.0,0.0,-0.024644150474934068,-0.025315400569475233,original_protean,0.9259273982940985,-0.024765848432222293,-0.02306243264434904
|
||||
|
@@ -0,0 +1,145 @@
|
||||
dataset,alpha,seed,variant,class_id,class_name,test_support,base_f1,variant_f1,delta_f1,base_recall,variant_recall,delta_recall
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,0,C&C,573,0.19558797985061663,0.29688838138738227,0.10130040153676564,0.9825479930191972,0.9075043630017452,-0.07504363001745196
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,1,Exfiltration,4427,0.9995482267901513,0.9995481247175779,-1.0207257339356346e-07,0.9995482267901513,0.999322340185227,-0.0002258866049242858
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,2,Exploitation,227,0.03455925277291302,0.029429192178550265,-0.005130060594362752,0.6519823788546255,0.6563876651982379,0.004405286343612369
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,3,Lateral_movement,6319,0.7004691086934823,0.6687793907176446,-0.03168971797583775,0.5553093843962652,0.5176451970248457,-0.03766418737141952
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,4,Normal,83651,0.9427787226987763,0.9586015558416595,0.01582283314288324,0.9177415691384443,0.9479384585958327,0.03019688945738841
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,5,RDOS,28252,0.9952464259838485,0.9942155631423466,-0.0010308628415018894,0.9967435933739204,0.9946906413705224,-0.0020529520033979454
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,6,Reconnaissance,25474,0.7694047991528076,0.7669666336944198,-0.00243816545838782,0.6274632959095549,0.6239695375677161,-0.0034937583418387375
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,7,Tampering,1024,0.6162227602905569,0.5744920993227992,-0.04173066096775768,0.994140625,0.994140625,0.0
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,8,Weaponization,12884,0.9023645530071718,0.9586139063327532,0.05624935332558145,0.9863396460726482,0.9833902514746973,-0.0029493945979509606
|
||||
xiiotid,0.25,3,v_cap__b1__c4,0,C&C,573,0.19558797985061663,0.1510164569215876,-0.04457152292902902,0.9825479930191972,0.680628272251309,-0.3019197207678882
|
||||
xiiotid,0.25,3,v_cap__b1__c4,1,Exfiltration,4427,0.9995482267901513,0.9808931860036832,-0.01865504078646807,0.9995482267901513,0.9625028235825616,-0.037045403207589755
|
||||
xiiotid,0.25,3,v_cap__b1__c4,2,Exploitation,227,0.03455925277291302,0.027462035100481952,-0.007097217672431065,0.6519823788546255,0.6651982378854625,0.013215859030836996
|
||||
xiiotid,0.25,3,v_cap__b1__c4,3,Lateral_movement,6319,0.7004691086934823,0.8096490432574589,0.10917993456397657,0.5553093843962652,0.706440892546289,0.15113150815002374
|
||||
xiiotid,0.25,3,v_cap__b1__c4,4,Normal,83651,0.9427787226987763,0.948727631530862,0.005948908832085764,0.9177415691384443,0.931034894980335,0.01329332584189069
|
||||
xiiotid,0.25,3,v_cap__b1__c4,5,RDOS,28252,0.9952464259838485,0.9936917461105007,-0.0015546798733477862,0.9967435933739204,0.9924607107461418,-0.004282882627778539
|
||||
xiiotid,0.25,3,v_cap__b1__c4,6,Reconnaissance,25474,0.7694047991528076,0.7667060839346477,-0.0026987152181598972,0.6274632959095549,0.6235769804506556,-0.003886315458899281
|
||||
xiiotid,0.25,3,v_cap__b1__c4,7,Tampering,1024,0.6162227602905569,0.8412353197042193,0.22501255941366238,0.994140625,0.9443359375,-0.0498046875
|
||||
xiiotid,0.25,3,v_cap__b1__c4,8,Weaponization,12884,0.9023645530071718,0.972830574450517,0.07046602144334524,0.9863396460726482,0.9601831729276622,-0.026156473144986037
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,0,C&C,573,0.19558797985061663,0.20091789903110657,0.005329919180489945,0.9825479930191972,0.68760907504363,-0.29493891797556715
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,1,Exfiltration,4427,0.9995482267901513,0.9994349644027574,-0.00011326238739395311,0.9995482267901513,0.9988705669753783,-0.0006776598147729684
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,2,Exploitation,227,0.03455925277291302,0.027697741425783063,-0.006861511347129954,0.6519823788546255,0.6563876651982379,0.004405286343612369
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,3,Lateral_movement,6319,0.7004691086934823,0.7297718853577696,0.029302776664287267,0.5553093843962652,0.592340560215224,0.03703117581895876
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,4,Normal,83651,0.9427787226987763,0.9550678067643374,0.012289084065561173,0.9177415691384443,0.9433479575856833,0.02560638844723906
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,5,RDOS,28252,0.9952464259838485,0.9928932210899425,-0.0023532048939060024,0.9967435933739204,0.9915050261928359,-0.005238567181084508
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,6,Reconnaissance,25474,0.7694047991528076,0.7662707609115489,-0.0031340382412586854,0.6274632959095549,0.6230274004867709,-0.0044358954227839975
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,7,Tampering,1024,0.6162227602905569,0.6616688396349413,0.04544607934438438,0.994140625,0.9912109375,-0.0029296875
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,8,Weaponization,12884,0.9023645530071718,0.9793060525906333,0.07694149958346153,0.9863396460726482,0.9770257683949084,-0.009313877677739835
|
||||
xiiotid,0.25,3,support_weighted__beta1,0,C&C,573,0.19558797985061663,0.15957228048529715,-0.03601569936531948,0.9825479930191972,0.6771378708551483,-0.30541012216404884
|
||||
xiiotid,0.25,3,support_weighted__beta1,1,Exfiltration,4427,0.9995482267901513,0.9992087713349157,-0.0003394554552356155,0.9995482267901513,0.9984187937655297,-0.001129433024621651
|
||||
xiiotid,0.25,3,support_weighted__beta1,2,Exploitation,227,0.03455925277291302,0.0239511332583186,-0.010608119514594418,0.6519823788546255,0.6563876651982379,0.004405286343612369
|
||||
xiiotid,0.25,3,support_weighted__beta1,3,Lateral_movement,6319,0.7004691086934823,0.6436087092405458,-0.05686039945293653,0.5553093843962652,0.4888431713878778,-0.0664662130083874
|
||||
xiiotid,0.25,3,support_weighted__beta1,4,Normal,83651,0.9427787226987763,0.9457320693052946,0.002953346606518359,0.9177415691384443,0.923635102987412,0.005893533848967736
|
||||
xiiotid,0.25,3,support_weighted__beta1,5,RDOS,28252,0.9952464259838485,0.9929812123360511,-0.002265213647797415,0.9967435933739204,0.9915050261928359,-0.005238567181084508
|
||||
xiiotid,0.25,3,support_weighted__beta1,6,Reconnaissance,25474,0.7694047991528076,0.7662337662337663,-0.0031710329190413056,0.6274632959095549,0.6230274004867709,-0.0044358954227839975
|
||||
xiiotid,0.25,3,support_weighted__beta1,7,Tampering,1024,0.6162227602905569,0.5461868958109559,-0.07003586447960097,0.994140625,0.9931640625,-0.0009765625
|
||||
xiiotid,0.25,3,support_weighted__beta1,8,Weaponization,12884,0.9023645530071718,0.9646464646464645,0.06228191163929275,0.9863396460726482,0.9339490841353617,-0.05239056193728653
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,0,C&C,573,0.21977597528003087,0.26217401338564505,0.04239803810561418,0.9930191972076788,0.9912739965095986,-0.0017452006980802626
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,1,Exfiltration,4427,0.9766797506349573,0.9704651162790697,-0.006214634355887538,0.9555003388299074,0.9426248023492206,-0.012875536480686733
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,2,Exploitation,227,0.04720962951383461,0.03136033229491174,-0.01584929721892287,0.6651982378854625,0.6651982378854625,0.0
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,3,Lateral_movement,6319,0.8849000425350915,0.9127720870678617,0.027872044532770257,0.8230732710871973,0.9025162209210318,0.07944294983383449
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,4,Normal,83651,0.9508570036837458,0.9540897802551446,0.0032327765713987544,0.9334257809231211,0.9391997704749495,0.005773989551828396
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,5,RDOS,28252,0.9948602009996997,0.995265184975796,0.00040498397609622927,0.99684978054651,0.9969913634432961,0.0001415828967861188
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,6,Reconnaissance,25474,0.7627515886631068,0.7634216004260057,0.0006700117628989366,0.6196121535683442,0.6190625736044595,-0.0005495799638847165
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,7,Tampering,1024,0.6814384308027607,0.8310552214324768,0.1496167906297161,0.916015625,0.7421875,-0.173828125
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,8,Weaponization,12884,0.8982495292558755,0.964573699698093,0.0663241704422175,0.999689537410742,0.9795094691089724,-0.02018006830176955
|
||||
xiiotid,0.25,4,v_cap__b1__c4,0,C&C,573,0.21977597528003087,0.019225284772433692,-0.2005506905075972,0.9930191972076788,1.0,0.006980802792321161
|
||||
xiiotid,0.25,4,v_cap__b1__c4,1,Exfiltration,4427,0.9766797506349573,0.9561424192407451,-0.02053733139421221,0.9555003388299074,0.91597018296815,-0.03953015586175734
|
||||
xiiotid,0.25,4,v_cap__b1__c4,2,Exploitation,227,0.04720962951383461,0.025953936060501892,-0.021255693453332718,0.6651982378854625,0.6651982378854625,0.0
|
||||
xiiotid,0.25,4,v_cap__b1__c4,3,Lateral_movement,6319,0.8849000425350915,0.8543103448275863,-0.030589697707505192,0.8230732710871973,0.7841430606108561,-0.038930210476341154
|
||||
xiiotid,0.25,4,v_cap__b1__c4,4,Normal,83651,0.9508570036837458,0.47602587077348524,-0.4748311329102606,0.9334257809231211,0.31278765346499143,-0.6206381274581296
|
||||
xiiotid,0.25,4,v_cap__b1__c4,5,RDOS,28252,0.9948602009996997,0.9941342217654043,-0.0007259792342954041,0.99684978054651,0.992814667988107,-0.004035112558402942
|
||||
xiiotid,0.25,4,v_cap__b1__c4,6,Reconnaissance,25474,0.7627515886631068,0.7467183551291804,-0.016033233533926383,0.6196121535683442,0.597354165031012,-0.022257988537332185
|
||||
xiiotid,0.25,4,v_cap__b1__c4,7,Tampering,1024,0.6814384308027607,0.7708719851576995,0.08943355435493883,0.916015625,0.8115234375,-0.1044921875
|
||||
xiiotid,0.25,4,v_cap__b1__c4,8,Weaponization,12884,0.8982495292558755,0.9351209001675844,0.03687137091170889,0.999689537410742,0.9095001552312947,-0.09018938217944727
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,0,C&C,573,0.21977597528003087,0.025710176195613086,-0.1940657990844178,0.9930191972076788,0.9982547993019197,0.005235602094240899
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,1,Exfiltration,4427,0.9766797506349573,0.9771256931608133,0.00044594252585605787,0.9555003388299074,0.9552744522249831,-0.0002258866049242858
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,2,Exploitation,227,0.04720962951383461,0.023436262866191604,-0.023773366647643006,0.6651982378854625,0.6519823788546255,-0.013215859030836996
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,3,Lateral_movement,6319,0.8849000425350915,0.8859115567976328,0.0010115142625413132,0.8230732710871973,0.8528248140528565,0.029751542965659183
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,4,Normal,83651,0.9508570036837458,0.652634283007811,-0.2982227206759348,0.9334257809231211,0.4859356134415608,-0.44749016748156034
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,5,RDOS,28252,0.9948602009996997,0.9940503594574495,-0.000809841542250278,0.99684978054651,0.9935225824720374,-0.0033271980744725704
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,6,Reconnaissance,25474,0.7627515886631068,0.7680698201456193,0.0053182314825125365,0.6196121535683442,0.6253042317657219,0.005692078197377715
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,7,Tampering,1024,0.6814384308027607,0.8291891891891893,0.1477507583864286,0.916015625,0.7490234375,-0.1669921875
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,8,Weaponization,12884,0.8982495292558755,0.8926873152551087,-0.005562214000766841,0.999689537410742,0.808677429369761,-0.191012108040981
|
||||
xiiotid,0.25,4,support_weighted__beta1,0,C&C,573,0.21977597528003087,0.0738276919063458,-0.14594828337368507,0.9930191972076788,0.987783595113438,-0.005235602094240788
|
||||
xiiotid,0.25,4,support_weighted__beta1,1,Exfiltration,4427,0.9766797506349573,0.8429168844746471,-0.1337628661603102,0.9555003388299074,0.7284843008809577,-0.22701603794894964
|
||||
xiiotid,0.25,4,support_weighted__beta1,2,Exploitation,227,0.04720962951383461,0.005032216385304568,-0.042177413128530045,0.6651982378854625,0.6519823788546255,-0.013215859030836996
|
||||
xiiotid,0.25,4,support_weighted__beta1,3,Lateral_movement,6319,0.8849000425350915,0.8383040711492754,-0.04659597138581606,0.8230732710871973,0.8651685393258427,0.0420952682386454
|
||||
xiiotid,0.25,4,support_weighted__beta1,4,Normal,83651,0.9508570036837458,0.45723444826220333,-0.4936225554215425,0.9334257809231211,0.2966850366403271,-0.636740744282794
|
||||
xiiotid,0.25,4,support_weighted__beta1,5,RDOS,28252,0.9948602009996997,0.9947536334633108,-0.00010656753638893512,0.99684978054651,0.9932748124026618,-0.0035749681438481673
|
||||
xiiotid,0.25,4,support_weighted__beta1,6,Reconnaissance,25474,0.7627515886631068,0.7785080905375368,0.015756501874430007,0.6196121535683442,0.6393185208447829,0.019706367276438708
|
||||
xiiotid,0.25,4,support_weighted__beta1,7,Tampering,1024,0.6814384308027607,0.019342359767891684,-0.662096071034869,0.916015625,0.009765625,-0.90625
|
||||
xiiotid,0.25,4,support_weighted__beta1,8,Weaponization,12884,0.8982495292558755,0.7824761572965205,-0.115773371959355,0.999689537410742,0.6972989754734554,-0.30239056193728653
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,0,Benign,95547,0.5529540050583834,0.5519122784416843,-0.0010417266166991013,0.3821260740787257,0.38113179900991134,-0.000994275068814332
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,1,HTTPFlood,28162,0.8921519550586796,0.9118123892470686,0.01966043418838903,0.8543427313401036,0.8587458277111001,0.004403096370996451
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,2,ICMPFlood,231,0.3996539792387543,0.5422535211267606,0.14259954188800633,1.0,1.0,0.0
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,3,SYNFlood,1944,0.8737464643867319,0.858948432760364,-0.014798031626367836,0.8739711934156379,0.8739711934156379,0.0
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,4,SYNScan,4009,0.9931412894375857,0.9941389200648459,0.0009976306272602153,0.9932651534048391,0.9942629084559741,0.0009977550511349742
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,5,SlowrateDoS,14625,0.8143951383174021,0.8544430422604574,0.04004790394305535,0.8796581196581197,0.9490598290598291,0.06940170940170942
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,6,TCPConnectScan,4010,0.848619957537155,0.8292531120331951,-0.01936684550395995,0.9967581047381546,0.9967581047381546,0.0
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,7,UDPFlood,91468,0.7627768118117493,0.7623921650343822,-0.0003846467773670481,1.0,1.0,0.0
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,8,UDPScan,3181,0.9814011159330439,0.9833825128125485,0.0019813968795046044,0.9952845017290161,0.9952845017290161,0.0
|
||||
5gnidd,0.5,3,v_cap__b1__c4,0,Benign,95547,0.5529540050583834,0.5550438944717918,0.0020898894134083745,0.3821260740787257,0.3841250902697102,0.001999016190984526
|
||||
5gnidd,0.5,3,v_cap__b1__c4,1,HTTPFlood,28162,0.8921519550586796,0.8941099122094598,0.0019579571507801763,0.8543427313401036,0.8209289112989134,-0.0334138200411902
|
||||
5gnidd,0.5,3,v_cap__b1__c4,2,ICMPFlood,231,0.3996539792387543,0.3902027027027027,-0.0094512765360516,1.0,1.0,0.0
|
||||
5gnidd,0.5,3,v_cap__b1__c4,3,SYNFlood,1944,0.8737464643867319,0.9018046709129511,0.028058206526219265,0.8739711934156379,0.8739711934156379,0.0
|
||||
5gnidd,0.5,3,v_cap__b1__c4,4,SYNScan,4009,0.9931412894375857,0.9931464174454829,5.128007897203801e-06,0.9932651534048391,0.9940134696931904,0.0007483162883512584
|
||||
5gnidd,0.5,3,v_cap__b1__c4,5,SlowrateDoS,14625,0.8143951383174021,0.8365808225658615,0.02218568424845946,0.8796581196581197,0.9673162393162393,0.08765811965811965
|
||||
5gnidd,0.5,3,v_cap__b1__c4,6,TCPConnectScan,4010,0.848619957537155,0.8594792339143534,0.010859276377198412,0.9967581047381546,0.9960099750623441,-0.0007481296758105049
|
||||
5gnidd,0.5,3,v_cap__b1__c4,7,UDPFlood,91468,0.7627768118117493,0.7626623308944614,-0.00011448091728782916,1.0,1.0,0.0
|
||||
5gnidd,0.5,3,v_cap__b1__c4,8,UDPScan,3181,0.9814011159330439,0.9841467205470935,0.0027456046140496015,0.9952845017290161,0.9952845017290161,0.0
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,0,Benign,95547,0.5529540050583834,0.5518354603049501,-0.0011185447534333148,0.3821260740787257,0.38105853663641975,-0.0010675374423059214
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,1,HTTPFlood,28162,0.8921519550586796,0.9147573805791134,0.022605425520433764,0.8543427313401036,0.8598466018038492,0.005503870463745564
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,2,ICMPFlood,231,0.3996539792387543,0.6015625,0.2019085207612457,1.0,1.0,0.0
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,3,SYNFlood,1944,0.8737464643867319,0.8679438058748404,-0.005802658511891434,0.8739711934156379,0.8739711934156379,0.0
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,4,SYNScan,4009,0.9931412894375857,0.994517817094443,0.0013765276568572515,0.9932651534048391,0.9955101022698928,0.002244948865053664
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,5,SlowrateDoS,14625,0.8143951383174021,0.8599392507593654,0.045544112441963325,0.8796581196581197,0.9582222222222222,0.07856410256410251
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,6,TCPConnectScan,4010,0.848619957537155,0.8175959079283888,-0.031024049608766258,0.9967581047381546,0.9965087281795512,-0.00024937655860346464
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,7,UDPFlood,91468,0.7627768118117493,0.7623667475141483,-0.00041006429760093166,1.0,1.0,0.0
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,8,UDPScan,3181,0.9814011159330439,0.9862928348909656,0.004891718957921731,0.9952845017290161,0.9952845017290161,0.0
|
||||
5gnidd,0.5,3,support_weighted__beta1,0,Benign,95547,0.5529540050583834,0.5562078318487121,0.0032538267903287066,0.3821260740787257,0.38524495797879577,0.0031188839000700908
|
||||
5gnidd,0.5,3,support_weighted__beta1,1,HTTPFlood,28162,0.8921519550586796,0.9776701074362755,0.08551815237759586,0.8543427313401036,0.9887792060222995,0.13443647468219588
|
||||
5gnidd,0.5,3,support_weighted__beta1,2,ICMPFlood,231,0.3996539792387543,0.9850746268656716,0.5854206476269173,1.0,1.0,0.0
|
||||
5gnidd,0.5,3,support_weighted__beta1,3,SYNFlood,1944,0.8737464643867319,0.8328431372549019,-0.04090332713182998,0.8739711934156379,0.8739711934156379,0.0
|
||||
5gnidd,0.5,3,support_weighted__beta1,4,SYNScan,4009,0.9931412894375857,0.9968824042898118,0.0037411148522260573,0.9932651534048391,0.9970067348465952,0.00374158144175607
|
||||
5gnidd,0.5,3,support_weighted__beta1,5,SlowrateDoS,14625,0.8143951383174021,0.9538612336343907,0.13946609531698861,0.8796581196581197,0.9315555555555556,0.051897435897435895
|
||||
5gnidd,0.5,3,support_weighted__beta1,6,TCPConnectScan,4010,0.848619957537155,0.8183587747157054,-0.030261182821449628,0.9967581047381546,0.9960099750623441,-0.0007481296758105049
|
||||
5gnidd,0.5,3,support_weighted__beta1,7,UDPFlood,91468,0.7627768118117493,0.7631491122680549,0.000372300456305652,1.0,1.0,0.0
|
||||
5gnidd,0.5,3,support_weighted__beta1,8,UDPScan,3181,0.9814011159330439,0.9856831621537504,0.0042820462207064924,0.9952845017290161,0.995598868280415,0.0003143665513989369
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,0,Benign,95547,0.5564678777807154,0.5582255083179297,0.0017576305372143386,0.38550660931269426,0.3871916439030006,0.0016850345903063335
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,1,HTTPFlood,28162,0.9678798586572438,0.9741026322786492,0.006222773621405442,0.972622683048079,0.9756764434344152,0.0030537603863362017
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,2,ICMPFlood,231,0.9148514851485148,0.911242603550296,-0.003608881598218816,1.0,1.0,0.0
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,3,SYNFlood,1944,0.870687384777456,0.8573651452282157,-0.013322239549240278,0.8503086419753086,0.8503086419753086,0.0
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,4,SYNScan,4009,0.997880034917072,0.9980044898977302,0.00012445498065816185,0.9980044898977302,0.9980044898977302,0.0
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,5,SlowrateDoS,14625,0.935706878672658,0.9481568007695744,0.012449922096916421,0.9254700854700855,0.9435213675213675,0.018051282051282036
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,6,TCPConnectScan,4010,0.7895882818685669,0.8084287306250634,0.018840448756496486,0.9947630922693267,0.9950124688279302,0.00024937655860346464
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,7,UDPFlood,91468,0.7635727672291811,0.7634739785484747,-9.878868070645197e-05,1.0,1.0,0.0
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,8,UDPScan,3181,0.9864801864801864,0.9880155642023346,0.001535377722148179,0.9977994341402074,0.9977994341402074,0.0
|
||||
5gnidd,0.5,4,v_cap__b1__c4,0,Benign,95547,0.5564678777807154,0.5587993514084241,0.002331473627708691,0.38550660931269426,0.38773587867750947,0.0022292693648152118
|
||||
5gnidd,0.5,4,v_cap__b1__c4,1,HTTPFlood,28162,0.9678798586572438,0.9785105856572297,0.010630726999985907,0.972622683048079,0.9830622825083446,0.010439599460265625
|
||||
5gnidd,0.5,4,v_cap__b1__c4,2,ICMPFlood,231,0.9148514851485148,0.8816793893129771,-0.03317209583553771,1.0,1.0,0.0
|
||||
5gnidd,0.5,4,v_cap__b1__c4,3,SYNFlood,1944,0.870687384777456,0.82025819265144,-0.05042919212601604,0.8503086419753086,0.8497942386831275,-0.0005144032921811093
|
||||
5gnidd,0.5,4,v_cap__b1__c4,4,SYNScan,4009,0.997880034917072,0.997880563520758,5.28603686045237e-07,0.9980044898977302,0.9982539286605139,0.0002494387627837158
|
||||
5gnidd,0.5,4,v_cap__b1__c4,5,SlowrateDoS,14625,0.935706878672658,0.9564676616915423,0.020760783018884288,0.9254700854700855,0.9464615384615385,0.020991452991452997
|
||||
5gnidd,0.5,4,v_cap__b1__c4,6,TCPConnectScan,4010,0.7895882818685669,0.827664869348818,0.03807658748025111,0.9947630922693267,0.9952618453865336,0.0004987531172069293
|
||||
5gnidd,0.5,4,v_cap__b1__c4,7,UDPFlood,91468,0.7635727672291811,0.7635313366055628,-4.1430623618277096e-05,1.0,1.0,0.0
|
||||
5gnidd,0.5,4,v_cap__b1__c4,8,UDPScan,3181,0.9864801864801864,0.9884735202492211,0.0019933337690346553,0.9977994341402074,0.9974850675888085,-0.0003143665513989369
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,0,Benign,95547,0.5564678777807154,0.5593643278777508,0.00289645009703543,0.38550660931269426,0.3882801134520184,0.0027735041393241455
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,1,HTTPFlood,28162,0.9678798586572438,0.9747545831922894,0.006874724535045562,0.972622683048079,0.9713798735885235,-0.0012428094595554606
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,2,ICMPFlood,231,0.9148514851485148,0.9041095890410958,-0.010741896107418936,1.0,1.0,0.0
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,3,SYNFlood,1944,0.870687384777456,0.8461735346813412,-0.024513850096114842,0.8503086419753086,0.8503086419753086,0.0
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,4,SYNScan,4009,0.997880034917072,0.998129442573887,0.0002494076568150261,0.9980044898977302,0.9982539286605139,0.0002494387627837158
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,5,SlowrateDoS,14625,0.935706878672658,0.950336757602558,0.014629878929899975,0.9254700854700855,0.9551452991452991,0.02967521367521364
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,6,TCPConnectScan,4010,0.7895882818685669,0.8173254147040754,0.027737132835508493,0.9947630922693267,0.9952618453865336,0.0004987531172069293
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,7,UDPFlood,91468,0.7635727672291811,0.7636588298156559,8.606258647481102e-05,1.0,1.0,0.0
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,8,UDPScan,3181,0.9864801864801864,0.9880155642023346,0.001535377722148179,0.9977994341402074,0.9977994341402074,0.0
|
||||
5gnidd,0.5,4,support_weighted__beta1,0,Benign,95547,0.5564678777807154,0.5587993514084241,0.002331473627708691,0.38550660931269426,0.38773587867750947,0.0022292693648152118
|
||||
5gnidd,0.5,4,support_weighted__beta1,1,HTTPFlood,28162,0.9678798586572438,0.9742469286149218,0.0063670699576779954,0.972622683048079,0.9658404942830765,-0.006782188765002473
|
||||
5gnidd,0.5,4,support_weighted__beta1,2,ICMPFlood,231,0.9148514851485148,0.7287066246056783,-0.18614486054283652,1.0,1.0,0.0
|
||||
5gnidd,0.5,4,support_weighted__beta1,3,SYNFlood,1944,0.870687384777456,0.8210735586481114,-0.04961382612934462,0.8503086419753086,0.8497942386831275,-0.0005144032921811093
|
||||
5gnidd,0.5,4,support_weighted__beta1,4,SYNScan,4009,0.997880034917072,0.998003992015968,0.00012395709889601036,0.9980044898977302,0.9977550511349463,-0.0002494387627838268
|
||||
5gnidd,0.5,4,support_weighted__beta1,5,SlowrateDoS,14625,0.935706878672658,0.9501515661839003,0.014444687511242282,0.9254700854700855,0.9644444444444444,0.03897435897435897
|
||||
5gnidd,0.5,4,support_weighted__beta1,6,TCPConnectScan,4010,0.7895882818685669,0.8417501317870323,0.0521618499184654,0.9947630922693267,0.9955112219451372,0.0007481296758105049
|
||||
5gnidd,0.5,4,support_weighted__beta1,7,UDPFlood,91468,0.7635727672291811,0.7633561029347331,-0.00021666429444799906,1.0,1.0,0.0
|
||||
5gnidd,0.5,4,support_weighted__beta1,8,UDPScan,3181,0.9864801864801864,0.9877042801556419,0.0012240936754555065,0.9977994341402074,0.9974850675888085,-0.0003143665513989369
|
||||
|
@@ -0,0 +1,161 @@
|
||||
dataset,alpha,seed,variant,client_id,n_samples,base_val_rare_f1,variant_val_rare_f1,delta_val_rare_f1
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,0,2140,0.8561962585138841,0.8375523410734678,-0.01864391744041638
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,1,18610,0.28169014084507044,0.3895131086142322,0.10782296776916178
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,2,1581,0.5283208020050125,0.536380531594081,0.00805972958906842
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,3,3178,0.8866432337434095,0.8850220264317181,-0.0016212073116913528
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,4,12935,0.5414469291532702,0.5653124500337164,0.023865520880446245
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,5,5628,0.6122881355932204,0.6888020833333333,0.07651394774011289
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,6,13609,0.6420664206642066,0.626865671641791,-0.015200749022415638
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,7,2268,0.9933548127265405,0.9943227899432279,0.000967977216687399
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,8,5176,0.47174934993403267,0.4315775645103299,-0.040171785423702755
|
||||
xiiotid,0.25,3,v_shrink__b1__lam0.5,9,16289,0.8829885544314278,0.8804212607716639,-0.002567293659763825
|
||||
xiiotid,0.25,3,v_cap__b1__c4,0,2140,0.8561962585138841,0.9140103780578206,0.05781411954393645
|
||||
xiiotid,0.25,3,v_cap__b1__c4,1,18610,0.28169014084507044,0.21875,-0.06294014084507044
|
||||
xiiotid,0.25,3,v_cap__b1__c4,2,1581,0.5283208020050125,0.5383390750600271,0.01001827305501457
|
||||
xiiotid,0.25,3,v_cap__b1__c4,3,3178,0.8866432337434095,0.886103781882146,-0.0005394518612634736
|
||||
xiiotid,0.25,3,v_cap__b1__c4,4,12935,0.5414469291532702,0.5196141652815423,-0.021832763871727945
|
||||
xiiotid,0.25,3,v_cap__b1__c4,5,5628,0.6122881355932204,0.629029029029029,0.016740893435808646
|
||||
xiiotid,0.25,3,v_cap__b1__c4,6,13609,0.6420664206642066,0.726643598615917,0.08457717795171038
|
||||
xiiotid,0.25,3,v_cap__b1__c4,7,2268,0.9933548127265405,0.9796953677153082,-0.013659445011232285
|
||||
xiiotid,0.25,3,v_cap__b1__c4,8,5176,0.47174934993403267,0.6828009194286191,0.21105156949458642
|
||||
xiiotid,0.25,3,v_cap__b1__c4,9,16289,0.8829885544314278,0.8799470726264877,-0.003041481804940016
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,0,2140,0.8561962585138841,0.8707592406090758,0.01456298209519169
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,1,18610,0.28169014084507044,0.2828282828282828,0.0011381419832123818
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,2,1581,0.5283208020050125,0.5399982514425599,0.011677449437547338
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,3,3178,0.8866432337434095,0.8850220264317181,-0.0016212073116913528
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,4,12935,0.5414469291532702,0.5417999072331323,0.0003529780798621207
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,5,5628,0.6122881355932204,0.647567517573067,0.03527938197984659
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,6,13609,0.6420664206642066,0.6666666666666666,0.024600246002460024
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,7,2268,0.9933548127265405,0.9930838079739626,-0.000271004752577908
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,8,5176,0.47174934993403267,0.4994349873234336,0.02768563738940094
|
||||
xiiotid,0.25,3,support_weighted__beta0.5,9,16289,0.8829885544314278,0.8793175531042194,-0.003671001327208323
|
||||
xiiotid,0.25,3,support_weighted__beta1,0,2140,0.8561962585138841,0.8255265538183227,-0.030669704695561406
|
||||
xiiotid,0.25,3,support_weighted__beta1,1,18610,0.28169014084507044,0.23098591549295774,-0.05070422535211269
|
||||
xiiotid,0.25,3,support_weighted__beta1,2,1581,0.5283208020050125,0.531031056751803,0.0027102547467904303
|
||||
xiiotid,0.25,3,support_weighted__beta1,3,3178,0.8866432337434095,0.8850220264317181,-0.0016212073116913528
|
||||
xiiotid,0.25,3,support_weighted__beta1,4,12935,0.5414469291532702,0.5323556211995784,-0.00909130795369184
|
||||
xiiotid,0.25,3,support_weighted__beta1,5,5628,0.6122881355932204,0.5699022093444405,-0.042385926248779904
|
||||
xiiotid,0.25,3,support_weighted__beta1,6,13609,0.6420664206642066,0.6060606060606061,-0.03600581460360053
|
||||
xiiotid,0.25,3,support_weighted__beta1,7,2268,0.9933548127265405,0.9808013355592654,-0.012553477167275062
|
||||
xiiotid,0.25,3,support_weighted__beta1,8,5176,0.47174934993403267,0.40165827142049576,-0.07009107851353691
|
||||
xiiotid,0.25,3,support_weighted__beta1,9,16289,0.8829885544314278,0.8801112439784262,-0.002877310453001547
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,0,2737,0.6914893617021277,0.8,0.10851063829787233
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,1,16337,0.030266608391608392,0.13058659217877094,0.10031998378716256
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,2,20397,0.9916883116883117,0.9899736147757255,-0.0017146969125861888
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,3,6530,0.8631578947368421,0.8400000000000001,-0.023157894736842044
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,4,7342,0.48807096365416736,0.4368949709744338,-0.05117599267973355
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,5,11939,0.4859075535512965,0.4811858608893957,-0.0047216926619008115
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,6,6280,0.8491131545208317,0.878584907422977,0.02947175290214532
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,7,7900,0.45493042952208107,0.4273399014778325,-0.027590528044248552
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,8,1256,0.19672131147540983,0.5714285714285715,0.3747072599531617
|
||||
xiiotid,0.25,4,v_shrink__b1__lam0.5,9,696,0.3725490196078431,0.31932773109243695,-0.05322128851540614
|
||||
xiiotid,0.25,4,v_cap__b1__c4,0,2737,0.6914893617021277,0.7638888888888888,0.07239952718676113
|
||||
xiiotid,0.25,4,v_cap__b1__c4,1,16337,0.030266608391608392,0.2650974577580082,0.2348308493663998
|
||||
xiiotid,0.25,4,v_cap__b1__c4,2,20397,0.9916883116883117,0.9509185632026322,-0.04076974848567949
|
||||
xiiotid,0.25,4,v_cap__b1__c4,3,6530,0.8631578947368421,0.8172043010752689,-0.045953593661573255
|
||||
xiiotid,0.25,4,v_cap__b1__c4,4,7342,0.48807096365416736,0.4566807056324985,-0.03139025802166884
|
||||
xiiotid,0.25,4,v_cap__b1__c4,5,11939,0.4859075535512965,0.4727694090382387,-0.013138144513057781
|
||||
xiiotid,0.25,4,v_cap__b1__c4,6,6280,0.8491131545208317,0.5698830559991757,-0.27923009852165603
|
||||
xiiotid,0.25,4,v_cap__b1__c4,7,7900,0.45493042952208107,0.3986569227730594,-0.05627350674902165
|
||||
xiiotid,0.25,4,v_cap__b1__c4,8,1256,0.19672131147540983,0.923076923076923,0.7263556116015132
|
||||
xiiotid,0.25,4,v_cap__b1__c4,9,696,0.3725490196078431,0.2773722627737226,-0.09517675683412047
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,0,2737,0.6914893617021277,0.8125,0.12101063829787229
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,1,16337,0.030266608391608392,0.40527704485488125,0.37501043646327287
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,2,20397,0.9916883116883117,0.8921739130434782,-0.09951439864483358
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,3,6530,0.8631578947368421,0.8247422680412372,-0.03841562669560494
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,4,7342,0.48807096365416736,0.4370553291427782,-0.05101563451138913
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,5,11939,0.4859075535512965,0.4858757062146893,-3.184733660721584e-05
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,6,6280,0.8491131545208317,0.6092359988392819,-0.23987715568154977
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,7,7900,0.45493042952208107,0.4038434194839712,-0.05108701003810989
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,8,1256,0.19672131147540983,0.8333333333333334,0.6366120218579235
|
||||
xiiotid,0.25,4,support_weighted__beta0.5,9,696,0.3725490196078431,0.24203821656050953,-0.13051080304733356
|
||||
xiiotid,0.25,4,support_weighted__beta1,0,2737,0.6914893617021277,0.0,-0.6914893617021277
|
||||
xiiotid,0.25,4,support_weighted__beta1,1,16337,0.030266608391608392,0.13121299272542716,0.10094638433381878
|
||||
xiiotid,0.25,4,support_weighted__beta1,2,20397,0.9916883116883117,0.827670645852464,-0.16401766583584776
|
||||
xiiotid,0.25,4,support_weighted__beta1,3,6530,0.8631578947368421,0.7321428571428571,-0.13101503759398503
|
||||
xiiotid,0.25,4,support_weighted__beta1,4,7342,0.48807096365416736,0.034514697996392535,-0.45355626565777485
|
||||
xiiotid,0.25,4,support_weighted__beta1,5,11939,0.4859075535512965,0.4083224967490247,-0.07758505680227179
|
||||
xiiotid,0.25,4,support_weighted__beta1,6,6280,0.8491131545208317,0.6507254064416463,-0.19838774807918536
|
||||
xiiotid,0.25,4,support_weighted__beta1,7,7900,0.45493042952208107,0.4015292906670286,-0.05340113885505249
|
||||
xiiotid,0.25,4,support_weighted__beta1,8,1256,0.19672131147540983,0.9090909090909091,0.7123695976154992
|
||||
xiiotid,0.25,4,support_weighted__beta1,9,696,0.3725490196078431,0.1958762886597938,-0.17667273094804928
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,0,8233,0.997275204359673,0.997275204359673,0.0
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,1,11855,1.0,1.0,0.0
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,2,3482,0.822289156626506,0.8629737609329445,0.0406846043064385
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,3,23984,0.5995379807039,0.6332307954013865,0.03369281469748653
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,4,23835,0.9813571961222968,0.9835575485799701,0.00220035245767336
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,5,14697,0.9188260179799048,0.9300813008130081,0.011255282833103286
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,6,13864,0.8424967110833235,0.8844401120994274,0.04194340101610394
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,7,2087,0.7710740265297389,0.8266129032258064,0.055538876696067496
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,8,14920,0.6668387602336143,0.6606425938471879,-0.006196166386426394
|
||||
5gnidd,0.5,3,v_shrink__b1__lam0.5,9,4632,0.804147465437788,0.8885630498533725,0.0844155844155845
|
||||
5gnidd,0.5,3,v_cap__b1__c4,0,8233,0.997275204359673,0.997275204359673,0.0
|
||||
5gnidd,0.5,3,v_cap__b1__c4,1,11855,1.0,1.0,0.0
|
||||
5gnidd,0.5,3,v_cap__b1__c4,2,3482,0.822289156626506,0.8698140200286122,0.047524863402106154
|
||||
5gnidd,0.5,3,v_cap__b1__c4,3,23984,0.5995379807039,0.5987810299244285,-0.0007569507794714658
|
||||
5gnidd,0.5,3,v_cap__b1__c4,4,23835,0.9813571961222968,0.9835575485799701,0.00220035245767336
|
||||
5gnidd,0.5,3,v_cap__b1__c4,5,14697,0.9188260179799048,0.9047131147540984,-0.014112903225806384
|
||||
5gnidd,0.5,3,v_cap__b1__c4,6,13864,0.8424967110833235,0.8319189061763319,-0.010577804906991561
|
||||
5gnidd,0.5,3,v_cap__b1__c4,7,2087,0.7710740265297389,0.8,0.028925973470261157
|
||||
5gnidd,0.5,3,v_cap__b1__c4,8,14920,0.6668387602336143,0.6608854511655734,-0.005953309068040924
|
||||
5gnidd,0.5,3,v_cap__b1__c4,9,4632,0.804147465437788,0.7900782013685239,-0.01406926406926412
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,0,8233,0.997275204359673,0.997275204359673,0.0
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,1,11855,1.0,1.0,0.0
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,2,3482,0.822289156626506,0.869942196531792,0.04765303990528591
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,3,23984,0.5995379807039,0.6328921430582934,0.03335416235439348
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,4,23835,0.9813571961222968,0.9894894894894894,0.008132293367192678
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,5,14697,0.9188260179799048,0.9424360400444939,0.023610022064589065
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,6,13864,0.8424967110833235,0.8964569058781104,0.053960194794786975
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,7,2087,0.7710740265297389,0.8444444444444446,0.07337041791470567
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,8,14920,0.6668387602336143,0.6606102627831439,-0.006228497450470383
|
||||
5gnidd,0.5,3,support_weighted__beta0.5,9,4632,0.804147465437788,0.893939393939394,0.089791928501606
|
||||
5gnidd,0.5,3,support_weighted__beta1,0,8233,0.997275204359673,0.997275204359673,0.0
|
||||
5gnidd,0.5,3,support_weighted__beta1,1,11855,1.0,1.0,0.0
|
||||
5gnidd,0.5,3,support_weighted__beta1,2,3482,0.822289156626506,0.9487603305785123,0.12647117395200624
|
||||
5gnidd,0.5,3,support_weighted__beta1,3,23984,0.5995379807039,0.9202334630350195,0.32069548233111955
|
||||
5gnidd,0.5,3,support_weighted__beta1,4,23835,0.9813571961222968,0.9894894894894894,0.008132293367192678
|
||||
5gnidd,0.5,3,support_weighted__beta1,5,14697,0.9188260179799048,0.956,0.03717398202009514
|
||||
5gnidd,0.5,3,support_weighted__beta1,6,13864,0.8424967110833235,0.9996466431095407,0.1571499320262172
|
||||
5gnidd,0.5,3,support_weighted__beta1,7,2087,0.7710740265297389,0.9444444444444444,0.17337041791470553
|
||||
5gnidd,0.5,3,support_weighted__beta1,8,14920,0.6668387602336143,0.679036517621346,0.012197757387731656
|
||||
5gnidd,0.5,3,support_weighted__beta1,9,4632,0.804147465437788,0.9946236559139785,0.19047619047619047
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,0,13066,0.9896907216494846,0.9795918367346939,-0.010098884914790718
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,1,17365,0.7715385486244764,0.772027397260274,0.0004888486357976785
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,2,1194,0.9745762711864406,0.9806866952789699,0.006110424092529265
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,3,5360,0.7272727272727272,0.7272727272727272,0.0
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,4,17032,0.9676691729323308,0.9648729446935725,-0.002796228238758247
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,5,3520,0.9864864864864865,0.9864864864864865,0.0
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,6,33983,0.6752988047808764,0.6904761904761905,0.015177385695314016
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,7,3343,0.9150326797385621,0.8705882352941177,-0.0444444444444444
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,8,17387,0.987171958429151,0.9893973501613671,0.002225391732216142
|
||||
5gnidd,0.5,4,v_shrink__b1__lam0.5,9,9339,0.9104573073233131,0.9191655801825294,0.00870827285921627
|
||||
5gnidd,0.5,4,v_cap__b1__c4,0,13066,0.9896907216494846,0.9696969696969697,-0.01999375195251485
|
||||
5gnidd,0.5,4,v_cap__b1__c4,1,17365,0.7715385486244764,0.7212821201539976,-0.05025642847047873
|
||||
5gnidd,0.5,4,v_cap__b1__c4,2,1194,0.9745762711864406,0.9806866952789699,0.006110424092529265
|
||||
5gnidd,0.5,4,v_cap__b1__c4,3,5360,0.7272727272727272,0.7272727272727272,0.0
|
||||
5gnidd,0.5,4,v_cap__b1__c4,4,17032,0.9676691729323308,0.966966966966967,-0.0007022059653637447
|
||||
5gnidd,0.5,4,v_cap__b1__c4,5,3520,0.9864864864864865,0.9864864864864865,0.0
|
||||
5gnidd,0.5,4,v_cap__b1__c4,6,33983,0.6752988047808764,0.71256038647343,0.03726158169255356
|
||||
5gnidd,0.5,4,v_cap__b1__c4,7,3343,0.9150326797385621,0.8705882352941177,-0.0444444444444444
|
||||
5gnidd,0.5,4,v_cap__b1__c4,8,17387,0.987171958429151,0.9914354230900994,0.004263464660948402
|
||||
5gnidd,0.5,4,v_cap__b1__c4,9,9339,0.9104573073233131,0.9183474300585557,0.007890122735242588
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,0,13066,0.9896907216494846,0.9795918367346939,-0.010098884914790718
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,1,17365,0.7715385486244764,0.7563099668362826,-0.015228581788193751
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,2,1194,0.9745762711864406,0.9806866952789699,0.006110424092529265
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,3,5360,0.7272727272727272,0.7272727272727272,0.0
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,4,17032,0.9676691729323308,0.9662668665667167,-0.0014023063656141144
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,5,3520,0.9864864864864865,0.9864864864864865,0.0
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,6,33983,0.6752988047808764,0.7018348623853211,0.026536057604444663
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,7,3343,0.9150326797385621,0.8705882352941177,-0.0444444444444444
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,8,17387,0.987171958429151,0.9890885925632715,0.0019166341341205761
|
||||
5gnidd,0.5,4,support_weighted__beta0.5,9,9339,0.9104573073233131,0.9020715630885123,-0.008385744234800763
|
||||
5gnidd,0.5,4,support_weighted__beta1,0,13066,0.9896907216494846,0.9056603773584906,-0.08403034429099399
|
||||
5gnidd,0.5,4,support_weighted__beta1,1,17365,0.7715385486244764,0.7214141414141414,-0.050124407210334954
|
||||
5gnidd,0.5,4,support_weighted__beta1,2,1194,0.9745762711864406,0.9827586206896552,0.008182349503214614
|
||||
5gnidd,0.5,4,support_weighted__beta1,3,5360,0.7272727272727272,0.7272727272727272,0.0
|
||||
5gnidd,0.5,4,support_weighted__beta1,4,17032,0.9676691729323308,0.7975124378109453,-0.17015673512138552
|
||||
5gnidd,0.5,4,support_weighted__beta1,5,3520,0.9864864864864865,0.9864864864864865,0.0
|
||||
5gnidd,0.5,4,support_weighted__beta1,6,33983,0.6752988047808764,0.7268041237113402,0.05150531893046373
|
||||
5gnidd,0.5,4,support_weighted__beta1,7,3343,0.9150326797385621,0.8686192468619247,-0.04641343287663735
|
||||
5gnidd,0.5,4,support_weighted__beta1,8,17387,0.987171958429151,0.9887660607350757,0.0015941023059247161
|
||||
5gnidd,0.5,4,support_weighted__beta1,9,9339,0.9104573073233131,0.8576271186440678,-0.05283018867924527
|
||||
|
@@ -0,0 +1,3 @@
|
||||
config,n_pairs,mean_delta_val_vs_original,sd_delta_val_vs_original,positive_pairs_val,mean_delta_test_vs_original,sd_delta_test_vs_original,positive_pairs_test
|
||||
support_weighted__beta0.5,4,0.01090766077956501,0.019000659916111093,2,0.012164986913594772,0.01990024144848278,3
|
||||
support_weighted__beta1,4,-0.016274987402244034,0.10395541030505347,1,-0.015464250464134077,0.10566381521436177,1
|
||||
|
@@ -0,0 +1,3 @@
|
||||
variant,n_pairs,mean_delta_val_vs_original,sd_delta_val_vs_original,positive_pairs_val_vs_original,mean_delta_test_vs_original,sd_delta_test_vs_original,positive_pairs_test_vs_original,mean_delta_val_vs_beta1,sd_delta_val_vs_beta1,mean_delta_test_vs_beta1,sd_delta_test_vs_beta1,mean_delta_val_vs_beta05,sd_delta_val_vs_beta05,mean_delta_test_vs_beta05,sd_delta_test_vs_beta05,mean_delta_val_vs_current_best,sd_delta_val_vs_current_best,positive_pairs_val_vs_current_best,mean_delta_test_vs_current_best,sd_delta_test_vs_current_best,positive_pairs_test_vs_current_best,improved_vs_original_per_plan,S1_val_deltas,S2_val_deltas
|
||||
v_shrink__b1__lam0.5,4,0.017994808339324264,0.014072367228704582,4,0.018354318695924132,0.014319068327916913,4,0.0342697957415683,0.10649767725215149,0.03381856916005821,0.1082507145556489,0.007087147559759255,0.023366313613711127,0.00618933178232936,0.024241921772951987,-0.01532128227473148,0.05206218407417258,2,-0.015455669432363206,0.052417393479881856,2,True,0.008456|0.032863,0.026902|0.003758
|
||||
v_cap__b1__c4,4,0.00467808081785806,0.02625027663765537,2,0.005868542758943829,0.025844914703010976,2,0.020953068220102095,0.09798314473745867,0.021332793223077906,0.09849148681223491,-0.006229579961706949,0.023343093528822526,-0.006296444154650943,0.023094240221471166,-0.028638009796197683,0.05968831126237434,1,-0.02794144536934351,0.059325448594970964,1,False,0.041031|-0.021430,0.001962|-0.002850
|
||||
|
@@ -0,0 +1,10 @@
|
||||
class_id,class_name,total,num_clients,n_missing_clients,min,max,mean,std,cv,max_min_ratio
|
||||
0,Benign,334415,10,0,1571,112226,33441.5,37695.7725116491,1.127215361501401,71.43602800763844
|
||||
1,HTTPFlood,98569,10,0,25,29013,9856.9,9965.921477214235,1.0110604223654736,1160.52
|
||||
2,ICMPFlood,808,10,0,1,303,80.8,84.37155918910115,1.044202465211648,303.0
|
||||
3,SYNFlood,6805,10,0,77,1688,680.5,557.1650114642878,0.8187582828277558,21.92207792207792
|
||||
4,SYNScan,14030,9,1,1,9592,1558.888888888889,2931.2507169179676,1.8803461477021888,9592.0
|
||||
5,SlowrateDoS,51187,10,0,28,20803,5118.7,7606.314338100943,1.48598557018402,742.9642857142857
|
||||
6,TCPConnectScan,14037,9,1,7,4056,1559.6666666666667,1501.5754689288476,0.962754094205288,579.4285714285714
|
||||
7,UDPFlood,320138,10,0,189,107583,32013.8,36126.15487371995,1.1284556932860188,569.2222222222222
|
||||
8,UDPScan,11134,10,0,5,8048,1113.4,2354.6204874671416,2.1148019467102044,1609.6
|
||||
|
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"alpha": 0.5,
|
||||
"created_utc": "2026-10-31T05:06:50Z",
|
||||
"dataset": "5gnidd",
|
||||
"manifest_content_hash": "bf212b0e11ba63d44be64c11215d085658d506065922a26960391eece1143b5b",
|
||||
"manifest_path": "/home/willtanoe/project/prototype-agregation/exploration_v2/partitions/5gnidd__alpha0.5__seed3.json",
|
||||
"num_classes": 9,
|
||||
"num_clients": 10,
|
||||
"partition_hash": "0739f15c51fe4fa2250f717e8f52548706cb7093581447cd43a4b2364f6ec058",
|
||||
"preprocessing_hash": "60b5682b39184fd7d24e117430a00c160c5c7e95d1bc1fcaa99745108f514d81",
|
||||
"procedure": "protean_research.data.pipeline.create_partition (per_class_dirichlet_multinomial), frozen split/preprocessing",
|
||||
"seed": 3
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
dataset,alpha,seed,client_id,class_id,class_name,N_ij,rare_flag,unseen_flag
|
||||
5gnidd,0.5,3,0,0,Benign,12367,False,False
|
||||
5gnidd,0.5,3,0,1,HTTPFlood,24330,False,False
|
||||
5gnidd,0.5,3,0,2,ICMPFlood,109,True,False
|
||||
5gnidd,0.5,3,0,3,SYNFlood,732,False,False
|
||||
5gnidd,0.5,3,0,4,SYNScan,1299,False,False
|
||||
5gnidd,0.5,3,0,5,SlowrateDoS,2036,False,False
|
||||
5gnidd,0.5,3,0,6,TCPConnectScan,261,False,False
|
||||
5gnidd,0.5,3,0,7,UDPFlood,107583,False,False
|
||||
5gnidd,0.5,3,0,8,UDPScan,129,True,False
|
||||
5gnidd,0.5,3,1,0,Benign,86013,False,False
|
||||
5gnidd,0.5,3,1,1,HTTPFlood,9922,False,False
|
||||
5gnidd,0.5,3,1,2,ICMPFlood,8,True,False
|
||||
5gnidd,0.5,3,1,3,SYNFlood,104,False,False
|
||||
5gnidd,0.5,3,1,4,SYNScan,31,False,False
|
||||
5gnidd,0.5,3,1,5,SlowrateDoS,3166,False,False
|
||||
5gnidd,0.5,3,1,6,TCPConnectScan,1928,False,False
|
||||
5gnidd,0.5,3,1,7,UDPFlood,6739,False,False
|
||||
5gnidd,0.5,3,1,8,UDPScan,5,True,False
|
||||
5gnidd,0.5,3,2,0,Benign,112226,False,False
|
||||
5gnidd,0.5,3,2,1,HTTPFlood,6136,False,False
|
||||
5gnidd,0.5,3,2,2,ICMPFlood,97,True,False
|
||||
5gnidd,0.5,3,2,3,SYNFlood,152,False,False
|
||||
5gnidd,0.5,3,2,4,SYNScan,143,False,False
|
||||
5gnidd,0.5,3,2,5,SlowrateDoS,28,True,False
|
||||
5gnidd,0.5,3,2,6,TCPConnectScan,966,False,False
|
||||
5gnidd,0.5,3,2,7,UDPFlood,13880,False,False
|
||||
5gnidd,0.5,3,2,8,UDPScan,301,False,False
|
||||
5gnidd,0.5,3,3,0,Benign,7322,False,False
|
||||
5gnidd,0.5,3,3,1,HTTPFlood,29013,False,False
|
||||
5gnidd,0.5,3,3,2,ICMPFlood,115,True,False
|
||||
5gnidd,0.5,3,3,3,SYNFlood,213,False,False
|
||||
5gnidd,0.5,3,3,4,SYNScan,9592,False,False
|
||||
5gnidd,0.5,3,3,5,SlowrateDoS,159,True,False
|
||||
5gnidd,0.5,3,3,6,TCPConnectScan,373,False,False
|
||||
5gnidd,0.5,3,3,7,UDPFlood,2354,False,False
|
||||
5gnidd,0.5,3,3,8,UDPScan,503,False,False
|
||||
5gnidd,0.5,3,4,0,Benign,28752,False,False
|
||||
5gnidd,0.5,3,4,1,HTTPFlood,497,False,False
|
||||
5gnidd,0.5,3,4,2,ICMPFlood,15,True,False
|
||||
5gnidd,0.5,3,4,3,SYNFlood,1688,False,False
|
||||
5gnidd,0.5,3,4,4,SYNScan,71,False,False
|
||||
5gnidd,0.5,3,4,5,SlowrateDoS,19630,False,False
|
||||
5gnidd,0.5,3,4,6,TCPConnectScan,0,False,True
|
||||
5gnidd,0.5,3,4,7,UDPFlood,607,False,False
|
||||
5gnidd,0.5,3,4,8,UDPScan,67,True,False
|
||||
5gnidd,0.5,3,5,0,Benign,11126,False,False
|
||||
5gnidd,0.5,3,5,1,HTTPFlood,366,False,False
|
||||
5gnidd,0.5,3,5,2,ICMPFlood,37,True,False
|
||||
5gnidd,0.5,3,5,3,SYNFlood,786,False,False
|
||||
5gnidd,0.5,3,5,4,SYNScan,519,False,False
|
||||
5gnidd,0.5,3,5,5,SlowrateDoS,1272,False,False
|
||||
5gnidd,0.5,3,5,6,TCPConnectScan,140,True,False
|
||||
5gnidd,0.5,3,5,7,UDPFlood,84223,False,False
|
||||
5gnidd,0.5,3,5,8,UDPScan,1613,False,False
|
||||
5gnidd,0.5,3,6,0,Benign,7958,False,False
|
||||
5gnidd,0.5,3,6,1,HTTPFlood,249,False,False
|
||||
5gnidd,0.5,3,6,2,ICMPFlood,40,True,False
|
||||
5gnidd,0.5,3,6,3,SYNFlood,912,False,False
|
||||
5gnidd,0.5,3,6,4,SYNScan,93,True,False
|
||||
5gnidd,0.5,3,6,5,SlowrateDoS,801,False,False
|
||||
5gnidd,0.5,3,6,6,TCPConnectScan,3851,False,False
|
||||
5gnidd,0.5,3,6,7,UDPFlood,45015,False,False
|
||||
5gnidd,0.5,3,6,8,UDPScan,8048,False,False
|
||||
5gnidd,0.5,3,7,0,Benign,64584,False,False
|
||||
5gnidd,0.5,3,7,1,HTTPFlood,25,False,False
|
||||
5gnidd,0.5,3,7,2,ICMPFlood,1,True,False
|
||||
5gnidd,0.5,3,7,3,SYNFlood,77,False,False
|
||||
5gnidd,0.5,3,7,4,SYNScan,2281,False,False
|
||||
5gnidd,0.5,3,7,5,SlowrateDoS,20803,False,False
|
||||
5gnidd,0.5,3,7,6,TCPConnectScan,7,True,False
|
||||
5gnidd,0.5,3,7,7,UDPFlood,12615,False,False
|
||||
5gnidd,0.5,3,7,8,UDPScan,17,False,False
|
||||
5gnidd,0.5,3,8,0,Benign,2496,False,False
|
||||
5gnidd,0.5,3,8,1,HTTPFlood,14929,False,False
|
||||
5gnidd,0.5,3,8,2,ICMPFlood,303,False,False
|
||||
5gnidd,0.5,3,8,3,SYNFlood,1582,False,False
|
||||
5gnidd,0.5,3,8,4,SYNScan,1,True,False
|
||||
5gnidd,0.5,3,8,5,SlowrateDoS,2192,False,False
|
||||
5gnidd,0.5,3,8,6,TCPConnectScan,2455,False,False
|
||||
5gnidd,0.5,3,8,7,UDPFlood,189,True,False
|
||||
5gnidd,0.5,3,8,8,UDPScan,234,False,False
|
||||
5gnidd,0.5,3,9,0,Benign,1571,False,False
|
||||
5gnidd,0.5,3,9,1,HTTPFlood,13102,False,False
|
||||
5gnidd,0.5,3,9,2,ICMPFlood,83,True,False
|
||||
5gnidd,0.5,3,9,3,SYNFlood,559,False,False
|
||||
5gnidd,0.5,3,9,4,SYNScan,0,False,True
|
||||
5gnidd,0.5,3,9,5,SlowrateDoS,1100,False,False
|
||||
5gnidd,0.5,3,9,6,TCPConnectScan,4056,False,False
|
||||
5gnidd,0.5,3,9,7,UDPFlood,46933,False,False
|
||||
5gnidd,0.5,3,9,8,UDPScan,217,True,False
|
||||
|
@@ -0,0 +1,10 @@
|
||||
class_id,class_name,total,num_clients,n_missing_clients,min,max,mean,std,cv,max_min_ratio
|
||||
0,Benign,334415,10,0,143,159078,33441.5,47131.86755317468,1.409382580122742,1112.4335664335665
|
||||
1,HTTPFlood,98569,10,0,4,47186,9856.9,14843.031647544243,1.5058519055224506,11796.5
|
||||
2,ICMPFlood,808,9,1,5,318,89.77777777777777,108.34284858497202,1.206789155030629,63.6
|
||||
3,SYNFlood,6805,10,0,7,2927,680.5,975.6094761737403,1.4336656519819844,418.14285714285717
|
||||
4,SYNScan,14030,10,0,45,8239,1403.0,2313.2844183109,1.6488128427019957,183.0888888888889
|
||||
5,SlowrateDoS,51187,10,0,7,22272,5118.7,6802.114951248619,1.3288754862071657,3181.714285714286
|
||||
6,TCPConnectScan,14037,10,0,1,5229,1403.7,1552.9292353484752,1.1063113452649962,5229.0
|
||||
7,UDPFlood,320138,10,0,6152,111407,32013.8,32088.759828949453,1.002341484889312,18.109070221066318
|
||||
8,UDPScan,11134,9,1,15,3055,1237.111111111111,1139.6573992451947,0.9212247703616627,203.66666666666666
|
||||
|
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"alpha": 0.5,
|
||||
"created_utc": "2026-10-31T05:07:28Z",
|
||||
"dataset": "5gnidd",
|
||||
"manifest_content_hash": "80fad04f10a0014a58ea97e87ab901d70cf48f29d99f5803510c0cd44b2618b9",
|
||||
"manifest_path": "/home/willtanoe/project/prototype-agregation/exploration_v2/partitions/5gnidd__alpha0.5__seed4.json",
|
||||
"num_classes": 9,
|
||||
"num_clients": 10,
|
||||
"partition_hash": "21a507d9d94f31154c5fb0c6833344738d1a137c78950f5284dec26d727e983a",
|
||||
"preprocessing_hash": "ffb7b2a1adb6cf8a292ea6e88dca574b44446da2b3ae18f690ae6fc59699e23d",
|
||||
"procedure": "protean_research.data.pipeline.create_partition (per_class_dirichlet_multinomial), frozen split/preprocessing",
|
||||
"seed": 4
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
dataset,alpha,seed,client_id,class_id,class_name,N_ij,rare_flag,unseen_flag
|
||||
5gnidd,0.5,4,0,0,Benign,159078,False,False
|
||||
5gnidd,0.5,4,0,1,HTTPFlood,11071,False,False
|
||||
5gnidd,0.5,4,0,2,ICMPFlood,39,True,False
|
||||
5gnidd,0.5,4,0,3,SYNFlood,936,False,False
|
||||
5gnidd,0.5,4,0,4,SYNScan,8239,False,False
|
||||
5gnidd,0.5,4,0,5,SlowrateDoS,1050,False,False
|
||||
5gnidd,0.5,4,0,6,TCPConnectScan,33,True,False
|
||||
5gnidd,0.5,4,0,7,UDPFlood,15599,False,False
|
||||
5gnidd,0.5,4,0,8,UDPScan,241,False,False
|
||||
5gnidd,0.5,4,1,0,Benign,15658,False,False
|
||||
5gnidd,0.5,4,1,1,HTTPFlood,27988,False,False
|
||||
5gnidd,0.5,4,1,2,ICMPFlood,318,False,False
|
||||
5gnidd,0.5,4,1,3,SYNFlood,7,True,False
|
||||
5gnidd,0.5,4,1,4,SYNScan,674,False,False
|
||||
5gnidd,0.5,4,1,5,SlowrateDoS,7,True,False
|
||||
5gnidd,0.5,4,1,6,TCPConnectScan,5229,False,False
|
||||
5gnidd,0.5,4,1,7,UDPFlood,6152,False,False
|
||||
5gnidd,0.5,4,1,8,UDPScan,93,False,False
|
||||
5gnidd,0.5,4,2,0,Benign,5874,False,False
|
||||
5gnidd,0.5,4,2,1,HTTPFlood,2211,False,False
|
||||
5gnidd,0.5,4,2,2,ICMPFlood,0,False,True
|
||||
5gnidd,0.5,4,2,3,SYNFlood,2113,False,False
|
||||
5gnidd,0.5,4,2,4,SYNScan,893,False,False
|
||||
5gnidd,0.5,4,2,5,SlowrateDoS,1049,False,False
|
||||
5gnidd,0.5,4,2,6,TCPConnectScan,490,True,False
|
||||
5gnidd,0.5,4,2,7,UDPFlood,13122,False,False
|
||||
5gnidd,0.5,4,2,8,UDPScan,131,True,False
|
||||
5gnidd,0.5,4,3,0,Benign,76962,False,False
|
||||
5gnidd,0.5,4,3,1,HTTPFlood,851,False,False
|
||||
5gnidd,0.5,4,3,2,ICMPFlood,10,True,False
|
||||
5gnidd,0.5,4,3,3,SYNFlood,26,True,False
|
||||
5gnidd,0.5,4,3,4,SYNScan,1223,False,False
|
||||
5gnidd,0.5,4,3,5,SlowrateDoS,7546,False,False
|
||||
5gnidd,0.5,4,3,6,TCPConnectScan,846,False,False
|
||||
5gnidd,0.5,4,3,7,UDPFlood,57683,False,False
|
||||
5gnidd,0.5,4,3,8,UDPScan,3055,False,False
|
||||
5gnidd,0.5,4,4,0,Benign,3588,False,False
|
||||
5gnidd,0.5,4,4,1,HTTPFlood,47186,False,False
|
||||
5gnidd,0.5,4,4,2,ICMPFlood,243,True,False
|
||||
5gnidd,0.5,4,4,3,SYNFlood,26,True,False
|
||||
5gnidd,0.5,4,4,4,SYNScan,930,False,False
|
||||
5gnidd,0.5,4,4,5,SlowrateDoS,11733,False,False
|
||||
5gnidd,0.5,4,4,6,TCPConnectScan,1121,False,False
|
||||
5gnidd,0.5,4,4,7,UDPFlood,22035,False,False
|
||||
5gnidd,0.5,4,4,8,UDPScan,1898,False,False
|
||||
5gnidd,0.5,4,5,0,Benign,26897,False,False
|
||||
5gnidd,0.5,4,5,1,HTTPFlood,235,False,False
|
||||
5gnidd,0.5,4,5,2,ICMPFlood,60,True,False
|
||||
5gnidd,0.5,4,5,3,SYNFlood,2927,False,False
|
||||
5gnidd,0.5,4,5,4,SYNScan,181,True,False
|
||||
5gnidd,0.5,4,5,5,SlowrateDoS,263,False,False
|
||||
5gnidd,0.5,4,5,6,TCPConnectScan,2914,False,False
|
||||
5gnidd,0.5,4,5,7,UDPFlood,58429,False,False
|
||||
5gnidd,0.5,4,5,8,UDPScan,2934,False,False
|
||||
5gnidd,0.5,4,6,0,Benign,143,False,False
|
||||
5gnidd,0.5,4,6,1,HTTPFlood,5129,False,False
|
||||
5gnidd,0.5,4,6,2,ICMPFlood,112,False,False
|
||||
5gnidd,0.5,4,6,3,SYNFlood,237,False,False
|
||||
5gnidd,0.5,4,6,4,SYNScan,45,True,False
|
||||
5gnidd,0.5,4,6,5,SlowrateDoS,5427,False,False
|
||||
5gnidd,0.5,4,6,6,TCPConnectScan,36,True,False
|
||||
5gnidd,0.5,4,6,7,UDPFlood,7654,False,False
|
||||
5gnidd,0.5,4,6,8,UDPScan,1444,False,False
|
||||
5gnidd,0.5,4,7,0,Benign,30083,False,False
|
||||
5gnidd,0.5,4,7,1,HTTPFlood,3124,False,False
|
||||
5gnidd,0.5,4,7,2,ICMPFlood,10,True,False
|
||||
5gnidd,0.5,4,7,3,SYNFlood,8,True,False
|
||||
5gnidd,0.5,4,7,4,SYNScan,79,False,False
|
||||
5gnidd,0.5,4,7,5,SlowrateDoS,357,False,False
|
||||
5gnidd,0.5,4,7,6,TCPConnectScan,1910,False,False
|
||||
5gnidd,0.5,4,7,7,UDPFlood,111407,False,False
|
||||
5gnidd,0.5,4,7,8,UDPScan,0,False,True
|
||||
5gnidd,0.5,4,8,0,Benign,405,False,False
|
||||
5gnidd,0.5,4,8,1,HTTPFlood,4,True,False
|
||||
5gnidd,0.5,4,8,2,ICMPFlood,5,False,False
|
||||
5gnidd,0.5,4,8,3,SYNFlood,413,False,False
|
||||
5gnidd,0.5,4,8,4,SYNScan,1110,False,False
|
||||
5gnidd,0.5,4,8,5,SlowrateDoS,1483,False,False
|
||||
5gnidd,0.5,4,8,6,TCPConnectScan,1,True,False
|
||||
5gnidd,0.5,4,8,7,UDPFlood,14987,False,False
|
||||
5gnidd,0.5,4,8,8,UDPScan,1323,False,False
|
||||
5gnidd,0.5,4,9,0,Benign,15727,False,False
|
||||
5gnidd,0.5,4,9,1,HTTPFlood,770,False,False
|
||||
5gnidd,0.5,4,9,2,ICMPFlood,11,True,False
|
||||
5gnidd,0.5,4,9,3,SYNFlood,112,False,False
|
||||
5gnidd,0.5,4,9,4,SYNScan,656,False,False
|
||||
5gnidd,0.5,4,9,5,SlowrateDoS,22272,False,False
|
||||
5gnidd,0.5,4,9,6,TCPConnectScan,1457,False,False
|
||||
5gnidd,0.5,4,9,7,UDPFlood,13070,False,False
|
||||
5gnidd,0.5,4,9,8,UDPScan,15,True,False
|
||||
|
@@ -0,0 +1,10 @@
|
||||
class_id,class_name,total,num_clients,n_missing_clients,min,max,mean,std,cv,max_min_ratio
|
||||
0,C&C,2004,8,2,4,1191,250.5,373.4360721730026,1.490762763165679,297.75
|
||||
1,Exfiltration,15494,10,0,2,5033,1549.4,1886.1375983739892,1.217334192832057,2516.5
|
||||
2,Exploitation,793,6,4,7,473,132.16666666666666,167.6011303329691,1.268104390917799,67.57142857142857
|
||||
3,Lateral_movement,22117,9,1,2,13685,2457.4444444444443,4284.391882457665,1.7434338717782243,6842.5
|
||||
4,Normal,292777,10,0,549,150706,29277.7,51810.80511254385,1.769633718240977,274.5100182149362
|
||||
5,RDOS,98883,10,0,9,58544,9888.3,17738.631790811825,1.7939010538527176,6504.888888888889
|
||||
6,Reconnaissance,89161,10,0,2,35323,8916.1,10550.735959638077,1.183335310240809,17661.5
|
||||
7,Tampering,3586,7,3,2,2013,512.2857142857143,687.5847406030795,1.3421899565592739,1006.5
|
||||
8,Weaponization,45094,10,0,31,25866,4509.4,7690.813119560246,1.7055069675700196,834.3870967741935
|
||||
|
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"alpha": 0.25,
|
||||
"created_utc": "2026-10-31T05:05:04Z",
|
||||
"dataset": "xiiotid",
|
||||
"manifest_content_hash": "1021d6ce77fdb0d4ddf940988f221fd85c8be4c2162d804e1c0da169ed9d7e2f",
|
||||
"manifest_path": "/home/willtanoe/project/prototype-agregation/exploration_v2/partitions/xiiotid__alpha0.25__seed3.json",
|
||||
"num_classes": 9,
|
||||
"num_clients": 10,
|
||||
"partition_hash": "85a8625b81d3624dec9e5322979e2f1547f330c60d5e822e32c12177195ed602",
|
||||
"preprocessing_hash": "e22db95e5109bfa02701d8ce450453a7c8f7e408c94e81dfe2b95ef4ab2a441f",
|
||||
"procedure": "protean_research.data.pipeline.create_partition (per_class_dirichlet_multinomial), frozen split/preprocessing",
|
||||
"seed": 3
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
dataset,alpha,seed,client_id,class_id,class_name,N_ij,rare_flag,unseen_flag
|
||||
xiiotid,0.25,3,0,0,C&C,21,False,False
|
||||
xiiotid,0.25,3,0,1,Exfiltration,1003,False,False
|
||||
xiiotid,0.25,3,0,2,Exploitation,0,False,True
|
||||
xiiotid,0.25,3,0,3,Lateral_movement,7,True,False
|
||||
xiiotid,0.25,3,0,4,Normal,2950,False,False
|
||||
xiiotid,0.25,3,0,5,RDOS,14,True,False
|
||||
xiiotid,0.25,3,0,6,Reconnaissance,11735,False,False
|
||||
xiiotid,0.25,3,0,7,Tampering,0,False,True
|
||||
xiiotid,0.25,3,0,8,Weaponization,342,False,False
|
||||
xiiotid,0.25,3,1,0,C&C,27,True,False
|
||||
xiiotid,0.25,3,1,1,Exfiltration,1029,False,False
|
||||
xiiotid,0.25,3,1,2,Exploitation,7,True,False
|
||||
xiiotid,0.25,3,1,3,Lateral_movement,199,False,False
|
||||
xiiotid,0.25,3,1,4,Normal,549,False,False
|
||||
xiiotid,0.25,3,1,5,RDOS,1426,False,False
|
||||
xiiotid,0.25,3,1,6,Reconnaissance,8567,False,False
|
||||
xiiotid,0.25,3,1,7,Tampering,370,False,False
|
||||
xiiotid,0.25,3,1,8,Weaponization,1278,False,False
|
||||
xiiotid,0.25,3,2,0,C&C,1191,False,False
|
||||
xiiotid,0.25,3,2,1,Exfiltration,483,False,False
|
||||
xiiotid,0.25,3,2,2,Exploitation,23,True,False
|
||||
xiiotid,0.25,3,2,3,Lateral_movement,5147,False,False
|
||||
xiiotid,0.25,3,2,4,Normal,17775,False,False
|
||||
xiiotid,0.25,3,2,5,RDOS,234,False,False
|
||||
xiiotid,0.25,3,2,6,Reconnaissance,139,False,False
|
||||
xiiotid,0.25,3,2,7,Tampering,0,False,True
|
||||
xiiotid,0.25,3,2,8,Weaponization,31,True,False
|
||||
xiiotid,0.25,3,3,0,C&C,0,False,True
|
||||
xiiotid,0.25,3,3,1,Exfiltration,2,True,False
|
||||
xiiotid,0.25,3,3,2,Exploitation,36,False,False
|
||||
xiiotid,0.25,3,3,3,Lateral_movement,0,False,True
|
||||
xiiotid,0.25,3,3,4,Normal,3006,False,False
|
||||
xiiotid,0.25,3,3,5,RDOS,58,False,False
|
||||
xiiotid,0.25,3,3,6,Reconnaissance,12,True,False
|
||||
xiiotid,0.25,3,3,7,Tampering,12,False,False
|
||||
xiiotid,0.25,3,3,8,Weaponization,1420,False,False
|
||||
xiiotid,0.25,3,4,0,C&C,15,True,False
|
||||
xiiotid,0.25,3,4,1,Exfiltration,18,True,False
|
||||
xiiotid,0.25,3,4,2,Exploitation,39,False,False
|
||||
xiiotid,0.25,3,4,3,Lateral_movement,2326,False,False
|
||||
xiiotid,0.25,3,4,4,Normal,2692,False,False
|
||||
xiiotid,0.25,3,4,5,RDOS,58544,False,False
|
||||
xiiotid,0.25,3,4,6,Reconnaissance,773,False,False
|
||||
xiiotid,0.25,3,4,7,Tampering,0,False,True
|
||||
xiiotid,0.25,3,4,8,Weaponization,25866,False,False
|
||||
xiiotid,0.25,3,5,0,C&C,320,True,False
|
||||
xiiotid,0.25,3,5,1,Exfiltration,4958,False,False
|
||||
xiiotid,0.25,3,5,2,Exploitation,0,False,True
|
||||
xiiotid,0.25,3,5,3,Lateral_movement,31,True,False
|
||||
xiiotid,0.25,3,5,4,Normal,966,False,False
|
||||
xiiotid,0.25,3,5,5,RDOS,18218,False,False
|
||||
xiiotid,0.25,3,5,6,Reconnaissance,3006,False,False
|
||||
xiiotid,0.25,3,5,7,Tampering,949,False,False
|
||||
xiiotid,0.25,3,5,8,Weaponization,8009,False,False
|
||||
xiiotid,0.25,3,6,0,C&C,0,False,True
|
||||
xiiotid,0.25,3,6,1,Exfiltration,2705,False,False
|
||||
xiiotid,0.25,3,6,2,Exploitation,215,False,False
|
||||
xiiotid,0.25,3,6,3,Lateral_movement,167,True,False
|
||||
xiiotid,0.25,3,6,4,Normal,1157,False,False
|
||||
xiiotid,0.25,3,6,5,RDOS,1247,False,False
|
||||
xiiotid,0.25,3,6,6,Reconnaissance,13942,False,False
|
||||
xiiotid,0.25,3,6,7,Tampering,2,True,False
|
||||
xiiotid,0.25,3,6,8,Weaponization,347,False,False
|
||||
xiiotid,0.25,3,7,0,C&C,165,False,False
|
||||
xiiotid,0.25,3,7,1,Exfiltration,35,True,False
|
||||
xiiotid,0.25,3,7,2,Exploitation,473,False,False
|
||||
xiiotid,0.25,3,7,3,Lateral_movement,13685,False,False
|
||||
xiiotid,0.25,3,7,4,Normal,111159,False,False
|
||||
xiiotid,0.25,3,7,5,RDOS,19011,False,False
|
||||
xiiotid,0.25,3,7,6,Reconnaissance,15662,False,False
|
||||
xiiotid,0.25,3,7,7,Tampering,2013,False,False
|
||||
xiiotid,0.25,3,7,8,Weaponization,120,True,False
|
||||
xiiotid,0.25,3,8,0,C&C,4,False,False
|
||||
xiiotid,0.25,3,8,1,Exfiltration,228,False,False
|
||||
xiiotid,0.25,3,8,2,Exploitation,0,False,True
|
||||
xiiotid,0.25,3,8,3,Lateral_movement,2,True,False
|
||||
xiiotid,0.25,3,8,4,Normal,150706,False,False
|
||||
xiiotid,0.25,3,8,5,RDOS,122,False,False
|
||||
xiiotid,0.25,3,8,6,Reconnaissance,35323,False,False
|
||||
xiiotid,0.25,3,8,7,Tampering,2,True,False
|
||||
xiiotid,0.25,3,8,8,Weaponization,83,False,False
|
||||
xiiotid,0.25,3,9,0,C&C,261,False,False
|
||||
xiiotid,0.25,3,9,1,Exfiltration,5033,False,False
|
||||
xiiotid,0.25,3,9,2,Exploitation,0,False,True
|
||||
xiiotid,0.25,3,9,3,Lateral_movement,553,False,False
|
||||
xiiotid,0.25,3,9,4,Normal,1817,False,False
|
||||
xiiotid,0.25,3,9,5,RDOS,9,True,False
|
||||
xiiotid,0.25,3,9,6,Reconnaissance,2,True,False
|
||||
xiiotid,0.25,3,9,7,Tampering,238,False,False
|
||||
xiiotid,0.25,3,9,8,Weaponization,7598,False,False
|
||||
|
@@ -0,0 +1,10 @@
|
||||
class_id,class_name,total,num_clients,n_missing_clients,min,max,mean,std,cv,max_min_ratio
|
||||
0,C&C,2004,9,1,1,1110,222.66666666666666,338.2435020316971,1.5190576438549273,1110.0
|
||||
1,Exfiltration,15494,10,0,1,7839,1549.4,2701.0935637256257,1.743315840793614,7839.0
|
||||
2,Exploitation,793,8,2,3,667,99.125,215.40568556795338,2.1730712289326948,222.33333333333334
|
||||
3,Lateral_movement,22117,9,1,11,9367,2457.4444444444443,3120.737203187417,1.2699115987107996,851.5454545454545
|
||||
4,Normal,292777,9,1,1,193448,32530.777777777777,58303.312956712805,1.7922508141364084,193448.0
|
||||
5,RDOS,98883,9,1,24,36163,10987.0,13856.277750936977,1.2611520661633728,1506.7916666666667
|
||||
6,Reconnaissance,89161,10,0,25,32287,8916.1,10687.687022457198,1.1986952840880203,1291.48
|
||||
7,Tampering,3586,10,0,3,2959,358.6,870.6838921215897,2.4280086227595916,986.3333333333334
|
||||
8,Weaponization,45094,10,0,4,18287,4509.4,6073.340385652693,1.3468178439820582,4571.75
|
||||
|
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"alpha": 0.25,
|
||||
"created_utc": "2026-10-31T05:06:13Z",
|
||||
"dataset": "xiiotid",
|
||||
"manifest_content_hash": "1ea850f1be9ddda24a69d192ef678cb337e62edb60978985615271a15d46d2c8",
|
||||
"manifest_path": "/home/willtanoe/project/prototype-agregation/exploration_v2/partitions/xiiotid__alpha0.25__seed4.json",
|
||||
"num_classes": 9,
|
||||
"num_clients": 10,
|
||||
"partition_hash": "ff47f504d5b604935333ccbfddd060c18d44d672104e5455f86dcefe48315887",
|
||||
"preprocessing_hash": "4837f4ab5939fe7bf7f83168d915e67d570086d8534a521a9a9827f10aa41086",
|
||||
"procedure": "protean_research.data.pipeline.create_partition (per_class_dirichlet_multinomial), frozen split/preprocessing",
|
||||
"seed": 4
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
dataset,alpha,seed,client_id,class_id,class_name,N_ij,rare_flag,unseen_flag
|
||||
xiiotid,0.25,4,0,0,C&C,1,True,False
|
||||
xiiotid,0.25,4,0,1,Exfiltration,109,False,False
|
||||
xiiotid,0.25,4,0,2,Exploitation,667,False,False
|
||||
xiiotid,0.25,4,0,3,Lateral_movement,156,False,False
|
||||
xiiotid,0.25,4,0,4,Normal,193448,False,False
|
||||
xiiotid,0.25,4,0,5,RDOS,29952,False,False
|
||||
xiiotid,0.25,4,0,6,Reconnaissance,1314,False,False
|
||||
xiiotid,0.25,4,0,7,Tampering,3,True,False
|
||||
xiiotid,0.25,4,0,8,Weaponization,9802,False,False
|
||||
xiiotid,0.25,4,1,0,C&C,20,False,False
|
||||
xiiotid,0.25,4,1,1,Exfiltration,368,False,False
|
||||
xiiotid,0.25,4,1,2,Exploitation,4,True,False
|
||||
xiiotid,0.25,4,1,3,Lateral_movement,1852,False,False
|
||||
xiiotid,0.25,4,1,4,Normal,13384,False,False
|
||||
xiiotid,0.25,4,1,5,RDOS,262,False,False
|
||||
xiiotid,0.25,4,1,6,Reconnaissance,1102,False,False
|
||||
xiiotid,0.25,4,1,7,Tampering,42,False,False
|
||||
xiiotid,0.25,4,1,8,Weaponization,4,True,False
|
||||
xiiotid,0.25,4,2,0,C&C,58,False,False
|
||||
xiiotid,0.25,4,2,1,Exfiltration,336,False,False
|
||||
xiiotid,0.25,4,2,2,Exploitation,0,False,True
|
||||
xiiotid,0.25,4,2,3,Lateral_movement,1331,False,False
|
||||
xiiotid,0.25,4,2,4,Normal,0,False,False
|
||||
xiiotid,0.25,4,2,5,RDOS,218,False,False
|
||||
xiiotid,0.25,4,2,6,Reconnaissance,32287,False,False
|
||||
xiiotid,0.25,4,2,7,Tampering,5,True,False
|
||||
xiiotid,0.25,4,2,8,Weaponization,27,True,False
|
||||
xiiotid,0.25,4,3,0,C&C,0,False,True
|
||||
xiiotid,0.25,4,3,1,Exfiltration,7839,False,False
|
||||
xiiotid,0.25,4,3,2,Exploitation,10,True,False
|
||||
xiiotid,0.25,4,3,3,Lateral_movement,11,True,False
|
||||
xiiotid,0.25,4,3,4,Normal,22325,False,False
|
||||
xiiotid,0.25,4,3,5,RDOS,619,False,False
|
||||
xiiotid,0.25,4,3,6,Reconnaissance,12186,False,False
|
||||
xiiotid,0.25,4,3,7,Tampering,2959,False,False
|
||||
xiiotid,0.25,4,3,8,Weaponization,7624,False,False
|
||||
xiiotid,0.25,4,4,0,C&C,413,False,False
|
||||
xiiotid,0.25,4,4,1,Exfiltration,94,False,False
|
||||
xiiotid,0.25,4,4,2,Exploitation,4,True,False
|
||||
xiiotid,0.25,4,4,3,Lateral_movement,9367,False,False
|
||||
xiiotid,0.25,4,4,4,Normal,13997,False,False
|
||||
xiiotid,0.25,4,4,5,RDOS,0,False,True
|
||||
xiiotid,0.25,4,4,6,Reconnaissance,1924,False,False
|
||||
xiiotid,0.25,4,4,7,Tampering,6,True,False
|
||||
xiiotid,0.25,4,4,8,Weaponization,47,False,False
|
||||
xiiotid,0.25,4,5,0,C&C,238,False,False
|
||||
xiiotid,0.25,4,5,1,Exfiltration,5,True,False
|
||||
xiiotid,0.25,4,5,2,Exploitation,3,True,False
|
||||
xiiotid,0.25,4,5,3,Lateral_movement,0,False,True
|
||||
xiiotid,0.25,4,5,4,Normal,1,False,False
|
||||
xiiotid,0.25,4,5,5,RDOS,24028,False,False
|
||||
xiiotid,0.25,4,5,6,Reconnaissance,22974,False,False
|
||||
xiiotid,0.25,4,5,7,Tampering,62,False,False
|
||||
xiiotid,0.25,4,5,8,Weaponization,5,False,False
|
||||
xiiotid,0.25,4,6,0,C&C,4,True,False
|
||||
xiiotid,0.25,4,6,1,Exfiltration,1,True,False
|
||||
xiiotid,0.25,4,6,2,Exploitation,50,False,False
|
||||
xiiotid,0.25,4,6,3,Lateral_movement,121,False,False
|
||||
xiiotid,0.25,4,6,4,Normal,167,False,False
|
||||
xiiotid,0.25,4,6,5,RDOS,36163,False,False
|
||||
xiiotid,0.25,4,6,6,Reconnaissance,14248,False,False
|
||||
xiiotid,0.25,4,6,7,Tampering,75,False,False
|
||||
xiiotid,0.25,4,6,8,Weaponization,18287,False,False
|
||||
xiiotid,0.25,4,7,0,C&C,1110,False,False
|
||||
xiiotid,0.25,4,7,1,Exfiltration,508,False,False
|
||||
xiiotid,0.25,4,7,2,Exploitation,47,True,False
|
||||
xiiotid,0.25,4,7,3,Lateral_movement,6770,False,False
|
||||
xiiotid,0.25,4,7,4,Normal,61,False,False
|
||||
xiiotid,0.25,4,7,5,RDOS,2656,False,False
|
||||
xiiotid,0.25,4,7,6,Reconnaissance,25,True,False
|
||||
xiiotid,0.25,4,7,7,Tampering,88,False,False
|
||||
xiiotid,0.25,4,7,8,Weaponization,147,False,False
|
||||
xiiotid,0.25,4,8,0,C&C,78,False,False
|
||||
xiiotid,0.25,4,8,1,Exfiltration,328,False,False
|
||||
xiiotid,0.25,4,8,2,Exploitation,0,False,True
|
||||
xiiotid,0.25,4,8,3,Lateral_movement,1112,False,False
|
||||
xiiotid,0.25,4,8,4,Normal,42050,False,False
|
||||
xiiotid,0.25,4,8,5,RDOS,24,True,False
|
||||
xiiotid,0.25,4,8,6,Reconnaissance,132,False,False
|
||||
xiiotid,0.25,4,8,7,Tampering,46,False,False
|
||||
xiiotid,0.25,4,8,8,Weaponization,10,True,False
|
||||
xiiotid,0.25,4,9,0,C&C,82,True,False
|
||||
xiiotid,0.25,4,9,1,Exfiltration,5906,False,False
|
||||
xiiotid,0.25,4,9,2,Exploitation,8,True,False
|
||||
xiiotid,0.25,4,9,3,Lateral_movement,1397,False,False
|
||||
xiiotid,0.25,4,9,4,Normal,7344,False,False
|
||||
xiiotid,0.25,4,9,5,RDOS,4961,False,False
|
||||
xiiotid,0.25,4,9,6,Reconnaissance,2969,False,False
|
||||
xiiotid,0.25,4,9,7,Tampering,300,False,False
|
||||
xiiotid,0.25,4,9,8,Weaponization,9141,False,False
|
||||
|
@@ -0,0 +1,3 @@
|
||||
condition,dataset,alpha,new_original_val_global,restored_original_val_global,sweep_beta0_val_global,new_minus_restored,new_minus_sweep_beta0
|
||||
S1,xiiotid,0.25,0.6380388187784778,0.6415812303524282,0.643275274917486,-0.0035424115739504103,-0.00523645613900825
|
||||
S2,5gnidd,0.5,0.8615257707605136,0.8694027416468965,0.8676517373672202,-0.00787697088638284,-0.006125966606706612
|
||||
|
@@ -0,0 +1,35 @@
|
||||
phase,run_id,dataset,alpha,seed,mode,beta,shrink_lambda,cap_factor,min_support,label,status,wall_s,peak_rss_kb,exit_code,notes
|
||||
screening,xiiotid__alpha0.25__seed0__original_protean,xiiotid,0.25,0,original_protean,,,,,original_protean,done,10879.00,8788432,0,
|
||||
screening,5gnidd__alpha0.5__seed0__original_protean,5gnidd,0.5,0,original_protean,,,,,original_protean,done,16807.00,10800928,0,
|
||||
screening,xiiotid__alpha0.25__seed0__v_beta__b1.5,xiiotid,0.25,0,v_beta,1.5,,,,v_beta__b1.5,done,11048.00,8788696,0,
|
||||
screening,xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5,xiiotid,0.25,0,v_shrink,1.0,0.5,,,v_shrink__b1__lam0.5,done,10965.00,8788104,0,
|
||||
screening,xiiotid__alpha0.25__seed0__v_cap__b1__c4,xiiotid,0.25,0,v_cap,1.0,,4,,v_cap__b1__c4,done,11022.00,8789080,0,
|
||||
screening,xiiotid__alpha0.25__seed0__v_cap__b1__c2,xiiotid,0.25,0,v_cap,1.0,,2,,v_cap__b1__c2,done,10960.00,8787984,0,
|
||||
screening,xiiotid__alpha0.25__seed0__v_minsup__t10,xiiotid,0.25,0,v_minsup,0.0,,,10,v_minsup__t10,done,10904.00,8788056,0,
|
||||
screening,xiiotid__alpha0.25__seed0__v_logweight,xiiotid,0.25,0,v_logweight,0.0,,,,v_logweight,done,10645.00,8787588,0,
|
||||
screening,5gnidd__alpha0.5__seed0__v_beta__b1.5,5gnidd,0.5,0,v_beta,1.5,,,,v_beta__b1.5,done,17571.00,10787996,0,
|
||||
screening,5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5,5gnidd,0.5,0,v_shrink,1.0,0.5,,,v_shrink__b1__lam0.5,done,17467.00,10791372,0,
|
||||
screening,5gnidd__alpha0.5__seed0__v_cap__b1__c4,5gnidd,0.5,0,v_cap,1.0,,4,,v_cap__b1__c4,done,16374.00,10795492,0,
|
||||
screening,5gnidd__alpha0.5__seed0__v_cap__b1__c2,5gnidd,0.5,0,v_cap,1.0,,2,,v_cap__b1__c2,done,15875.00,10794444,0,
|
||||
screening,5gnidd__alpha0.5__seed0__v_minsup__t10,5gnidd,0.5,0,v_minsup,0.0,,,10,v_minsup__t10,done,16232.00,10787860,0,
|
||||
screening,5gnidd__alpha0.5__seed0__v_logweight,5gnidd,0.5,0,v_logweight,0.0,,,,v_logweight,done,17342.00,10806700,0,
|
||||
confirm,xiiotid__alpha0.25__seed3__original_protean,xiiotid,0.25,3,original_protean,,,,,original_protean,done,11102.00,10986852,0,
|
||||
confirm,xiiotid__alpha0.25__seed3__support_weighted__beta0.5,xiiotid,0.25,3,support_weighted,0.5,,,,support_weighted__beta0.5,done,11105.00,10986972,0,
|
||||
confirm,xiiotid__alpha0.25__seed3__support_weighted__beta1,xiiotid,0.25,3,support_weighted,1,,,,support_weighted__beta1,done,11247.00,10986812,0,
|
||||
confirm,xiiotid__alpha0.25__seed3__v_shrink__b1__lam0.5,xiiotid,0.25,3,v_shrink,1.0,0.5,,,v_shrink__b1__lam0.5,done,10678.00,10986572,0,
|
||||
confirm,xiiotid__alpha0.25__seed3__v_cap__b1__c4,xiiotid,0.25,3,v_cap,1.0,,4,,v_cap__b1__c4,done,10621.00,10986660,0,
|
||||
confirm,xiiotid__alpha0.25__seed4__original_protean,xiiotid,0.25,4,original_protean,,,,,original_protean,done,11200.00,13373900,0,
|
||||
confirm,xiiotid__alpha0.25__seed4__support_weighted__beta0.5,xiiotid,0.25,4,support_weighted,0.5,,,,support_weighted__beta0.5,done,11147.00,13376792,0,
|
||||
confirm,xiiotid__alpha0.25__seed4__support_weighted__beta1,xiiotid,0.25,4,support_weighted,1,,,,support_weighted__beta1,done,11529.00,13377304,0,
|
||||
confirm,xiiotid__alpha0.25__seed4__v_shrink__b1__lam0.5,xiiotid,0.25,4,v_shrink,1.0,0.5,,,v_shrink__b1__lam0.5,done,11448.00,13377596,0,
|
||||
confirm,xiiotid__alpha0.25__seed4__v_cap__b1__c4,xiiotid,0.25,4,v_cap,1.0,,4,,v_cap__b1__c4,done,10168.00,13377208,0,
|
||||
confirm,5gnidd__alpha0.5__seed3__original_protean,5gnidd,0.5,3,original_protean,,,,,original_protean,done,15875.00,9482756,0,
|
||||
confirm,5gnidd__alpha0.5__seed3__support_weighted__beta0.5,5gnidd,0.5,3,support_weighted,0.5,,,,support_weighted__beta0.5,done,16116.00,9507836,0,
|
||||
confirm,5gnidd__alpha0.5__seed3__support_weighted__beta1,5gnidd,0.5,3,support_weighted,1,,,,support_weighted__beta1,done,16782.00,9480524,0,
|
||||
confirm,5gnidd__alpha0.5__seed3__v_shrink__b1__lam0.5,5gnidd,0.5,3,v_shrink,1.0,0.5,,,v_shrink__b1__lam0.5,done,16459.00,9501568,0,
|
||||
confirm,5gnidd__alpha0.5__seed3__v_cap__b1__c4,5gnidd,0.5,3,v_cap,1.0,,4,,v_cap__b1__c4,done,17023.00,9487356,0,
|
||||
confirm,5gnidd__alpha0.5__seed4__original_protean,5gnidd,0.5,4,original_protean,,,,,original_protean,done,17324.00,11657012,0,
|
||||
confirm,5gnidd__alpha0.5__seed4__support_weighted__beta0.5,5gnidd,0.5,4,support_weighted,0.5,,,,support_weighted__beta0.5,done,17181.00,11697428,0,
|
||||
confirm,5gnidd__alpha0.5__seed4__support_weighted__beta1,5gnidd,0.5,4,support_weighted,1,,,,support_weighted__beta1,done,17582.00,11669892,0,
|
||||
confirm,5gnidd__alpha0.5__seed4__v_shrink__b1__lam0.5,5gnidd,0.5,4,v_shrink,1.0,0.5,,,v_shrink__b1__lam0.5,done,17234.00,11688404,0,
|
||||
confirm,5gnidd__alpha0.5__seed4__v_cap__b1__c4,5gnidd,0.5,4,v_cap,1.0,,4,,v_cap__b1__c4,done,16415.00,11679488,0,
|
||||
|
@@ -0,0 +1,15 @@
|
||||
run_id,dataset,alpha,manifest_content_hash,preprocessing_hash,support_sha256,snapshot0_sha256
|
||||
5gnidd__alpha0.5__seed0__original_protean,5gnidd,0.5,0732582cf4510089212717816d2151f5706c7b361123be32cc353bdf4b7f78e6,ff8bc0e52967a2a081392282ae62ec86bc3f2b88648a9fa20de43fb0e7e2cc3a,a11f2d89f27753692268ebea60abca47e8ef2900f622b1d371ddc3817238b346,6143d1f99515b903c5602afcc776613db658b3b2e6af35272f57e858c4e73fef
|
||||
5gnidd__alpha0.5__seed0__v_beta__b1.5,5gnidd,0.5,0732582cf4510089212717816d2151f5706c7b361123be32cc353bdf4b7f78e6,ff8bc0e52967a2a081392282ae62ec86bc3f2b88648a9fa20de43fb0e7e2cc3a,a11f2d89f27753692268ebea60abca47e8ef2900f622b1d371ddc3817238b346,6143d1f99515b903c5602afcc776613db658b3b2e6af35272f57e858c4e73fef
|
||||
5gnidd__alpha0.5__seed0__v_cap__b1__c2,5gnidd,0.5,0732582cf4510089212717816d2151f5706c7b361123be32cc353bdf4b7f78e6,ff8bc0e52967a2a081392282ae62ec86bc3f2b88648a9fa20de43fb0e7e2cc3a,a11f2d89f27753692268ebea60abca47e8ef2900f622b1d371ddc3817238b346,6143d1f99515b903c5602afcc776613db658b3b2e6af35272f57e858c4e73fef
|
||||
5gnidd__alpha0.5__seed0__v_cap__b1__c4,5gnidd,0.5,0732582cf4510089212717816d2151f5706c7b361123be32cc353bdf4b7f78e6,ff8bc0e52967a2a081392282ae62ec86bc3f2b88648a9fa20de43fb0e7e2cc3a,a11f2d89f27753692268ebea60abca47e8ef2900f622b1d371ddc3817238b346,6143d1f99515b903c5602afcc776613db658b3b2e6af35272f57e858c4e73fef
|
||||
5gnidd__alpha0.5__seed0__v_logweight,5gnidd,0.5,0732582cf4510089212717816d2151f5706c7b361123be32cc353bdf4b7f78e6,ff8bc0e52967a2a081392282ae62ec86bc3f2b88648a9fa20de43fb0e7e2cc3a,a11f2d89f27753692268ebea60abca47e8ef2900f622b1d371ddc3817238b346,6143d1f99515b903c5602afcc776613db658b3b2e6af35272f57e858c4e73fef
|
||||
5gnidd__alpha0.5__seed0__v_minsup__t10,5gnidd,0.5,0732582cf4510089212717816d2151f5706c7b361123be32cc353bdf4b7f78e6,ff8bc0e52967a2a081392282ae62ec86bc3f2b88648a9fa20de43fb0e7e2cc3a,a11f2d89f27753692268ebea60abca47e8ef2900f622b1d371ddc3817238b346,6143d1f99515b903c5602afcc776613db658b3b2e6af35272f57e858c4e73fef
|
||||
5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5,5gnidd,0.5,0732582cf4510089212717816d2151f5706c7b361123be32cc353bdf4b7f78e6,ff8bc0e52967a2a081392282ae62ec86bc3f2b88648a9fa20de43fb0e7e2cc3a,a11f2d89f27753692268ebea60abca47e8ef2900f622b1d371ddc3817238b346,6143d1f99515b903c5602afcc776613db658b3b2e6af35272f57e858c4e73fef
|
||||
xiiotid__alpha0.25__seed0__original_protean,xiiotid,0.25,839ba18e2d87245d198be8f5f89d4a24f13cdb6fc64c004d406c6d4f8246f3da,8580cee41c698ce43cf3269e4a2b3a01c92d6df22820f4004c0267478bd2579a,dcd8864b78dc46d2f727be6596903c6944d0e9acd6cce994b61f0689339c3349,5aaa79e7c7266b9ea0331b890bddac5794033f452a18971c192c627e6f4c1f00
|
||||
xiiotid__alpha0.25__seed0__v_beta__b1.5,xiiotid,0.25,839ba18e2d87245d198be8f5f89d4a24f13cdb6fc64c004d406c6d4f8246f3da,8580cee41c698ce43cf3269e4a2b3a01c92d6df22820f4004c0267478bd2579a,dcd8864b78dc46d2f727be6596903c6944d0e9acd6cce994b61f0689339c3349,5aaa79e7c7266b9ea0331b890bddac5794033f452a18971c192c627e6f4c1f00
|
||||
xiiotid__alpha0.25__seed0__v_cap__b1__c2,xiiotid,0.25,839ba18e2d87245d198be8f5f89d4a24f13cdb6fc64c004d406c6d4f8246f3da,8580cee41c698ce43cf3269e4a2b3a01c92d6df22820f4004c0267478bd2579a,dcd8864b78dc46d2f727be6596903c6944d0e9acd6cce994b61f0689339c3349,5aaa79e7c7266b9ea0331b890bddac5794033f452a18971c192c627e6f4c1f00
|
||||
xiiotid__alpha0.25__seed0__v_cap__b1__c4,xiiotid,0.25,839ba18e2d87245d198be8f5f89d4a24f13cdb6fc64c004d406c6d4f8246f3da,8580cee41c698ce43cf3269e4a2b3a01c92d6df22820f4004c0267478bd2579a,dcd8864b78dc46d2f727be6596903c6944d0e9acd6cce994b61f0689339c3349,5aaa79e7c7266b9ea0331b890bddac5794033f452a18971c192c627e6f4c1f00
|
||||
xiiotid__alpha0.25__seed0__v_logweight,xiiotid,0.25,839ba18e2d87245d198be8f5f89d4a24f13cdb6fc64c004d406c6d4f8246f3da,8580cee41c698ce43cf3269e4a2b3a01c92d6df22820f4004c0267478bd2579a,dcd8864b78dc46d2f727be6596903c6944d0e9acd6cce994b61f0689339c3349,5aaa79e7c7266b9ea0331b890bddac5794033f452a18971c192c627e6f4c1f00
|
||||
xiiotid__alpha0.25__seed0__v_minsup__t10,xiiotid,0.25,839ba18e2d87245d198be8f5f89d4a24f13cdb6fc64c004d406c6d4f8246f3da,8580cee41c698ce43cf3269e4a2b3a01c92d6df22820f4004c0267478bd2579a,dcd8864b78dc46d2f727be6596903c6944d0e9acd6cce994b61f0689339c3349,5aaa79e7c7266b9ea0331b890bddac5794033f452a18971c192c627e6f4c1f00
|
||||
xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5,xiiotid,0.25,839ba18e2d87245d198be8f5f89d4a24f13cdb6fc64c004d406c6d4f8246f3da,8580cee41c698ce43cf3269e4a2b3a01c92d6df22820f4004c0267478bd2579a,dcd8864b78dc46d2f727be6596903c6944d0e9acd6cce994b61f0689339c3349,5aaa79e7c7266b9ea0331b890bddac5794033f452a18971c192c627e6f4c1f00
|
||||
|
@@ -0,0 +1,7 @@
|
||||
rank,rank_secondary,label,mode,beta,shrink_lambda,cap_factor,min_support,score_mean_delta_val_global,min_condition_delta,secondary_mean_delta_val_per_client,S1_val_global,S1_baseline,S1_delta,S1_val_per_client,S1_delta_per_client,S2_val_global,S2_baseline,S2_delta,S2_val_per_client,S2_delta_per_client
|
||||
1,1,v_shrink__b1__lam0.5,v_shrink,1.0,0.5,,,0.02666418343657906,0.01418010949105697,0.02904392091826946,0.6771870761605789,0.6380388187784778,0.03914825738210115,0.6394200514807982,0.0314475437388545,0.8757058802515706,0.8615257707605136,0.01418010949105697,0.7519195999208417,0.026640298097684423
|
||||
2,2,v_cap__b1__c4,v_cap,1.0,,4.0,,0.006386658832843839,0.0034615578813887993,0.014884565739555988,0.6415003766598666,0.6380388187784778,0.0034615578813887993,0.6043797897480034,-0.003592717993940231,0.8708375305448125,0.8615257707605136,0.009311759784298879,0.7586411512962095,0.03336184947305221
|
||||
3,3,v_cap__b1__c2,v_cap,1.0,,2.0,,-0.0024310752295784166,-0.0055917994582352915,-0.013098515805364142,0.6324470193202425,0.6380388187784778,-0.0055917994582352915,0.5746261281359909,-0.03334637960595277,0.8622554197595921,0.8615257707605136,0.0007296489990784583,0.7324286498183817,0.0071493479952244865
|
||||
4,5,v_logweight,v_logweight,0.0,,,,-0.013930127799255287,-0.034591638342140296,-0.030092848616604162,0.6447702015221075,0.6380388187784778,0.006731382743629721,0.6126459310493659,0.004673423307422264,0.8269341324183733,0.8615257707605136,-0.034591638342140296,0.6604201812825267,-0.06485912054063059
|
||||
5,6,v_minsup__t10,v_minsup,0.0,,,10.0,-0.03017797764203456,-0.04375397523698199,-0.05005934390012601,0.6214368387313907,0.6380388187784778,-0.016601980047087128,0.581752384882787,-0.026220122859156647,0.8177717955235316,0.8615257707605136,-0.04375397523698199,0.6513807368820619,-0.07389856494109537
|
||||
6,4,v_beta__b1.5,v_beta,1.5,,,,-0.04850986532623136,-0.09180491842510796,-0.026127080317370543,0.5462339003533698,0.6380388187784778,-0.09180491842510796,0.554598371814126,-0.0533741359278177,0.8563109585331589,0.8615257707605136,-0.005214812227354759,0.7263992771162339,0.0011199752930766138
|
||||
|
@@ -0,0 +1,3 @@
|
||||
condition,baseline_run,baseline_val_global,best_beta_by_val_global,best_val_global,best_delta_global,best_beta_by_val_per_client,best_val_per_client,best_delta_per_client
|
||||
S1,xiiotid__alpha0.25__seed0__original_protean,0.6380388187784778,0.75,0.6690666806848056,0.03102786190632778,0.75,0.6564371328240081,0.048464625082064394
|
||||
S2,5gnidd__alpha0.5__seed0__original_protean,0.8615257707605136,1.0,0.8762664919755059,0.014740721214992258,0.75,0.7719208198370514,0.046641518013894157
|
||||
|
@@ -0,0 +1,35 @@
|
||||
phase,run_id,status,wall_s,wall_h,peak_rss_gib
|
||||
screening,xiiotid__alpha0.25__seed0__original_protean,done,10879.00,3.022,8.381
|
||||
screening,5gnidd__alpha0.5__seed0__original_protean,done,16807.00,4.669,10.301
|
||||
screening,xiiotid__alpha0.25__seed0__v_beta__b1.5,done,11048.00,3.069,8.382
|
||||
screening,xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5,done,10965.00,3.046,8.381
|
||||
screening,xiiotid__alpha0.25__seed0__v_cap__b1__c4,done,11022.00,3.062,8.382
|
||||
screening,xiiotid__alpha0.25__seed0__v_cap__b1__c2,done,10960.00,3.044,8.381
|
||||
screening,xiiotid__alpha0.25__seed0__v_minsup__t10,done,10904.00,3.029,8.381
|
||||
screening,xiiotid__alpha0.25__seed0__v_logweight,done,10645.00,2.957,8.38
|
||||
screening,5gnidd__alpha0.5__seed0__v_beta__b1.5,done,17571.00,4.881,10.288
|
||||
screening,5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5,done,17467.00,4.852,10.291
|
||||
screening,5gnidd__alpha0.5__seed0__v_cap__b1__c4,done,16374.00,4.548,10.295
|
||||
screening,5gnidd__alpha0.5__seed0__v_cap__b1__c2,done,15875.00,4.41,10.294
|
||||
screening,5gnidd__alpha0.5__seed0__v_minsup__t10,done,16232.00,4.509,10.288
|
||||
screening,5gnidd__alpha0.5__seed0__v_logweight,done,17342.00,4.817,10.306
|
||||
confirm,xiiotid__alpha0.25__seed3__original_protean,done,11102.00,3.084,10.478
|
||||
confirm,xiiotid__alpha0.25__seed3__support_weighted__beta0.5,done,11105.00,3.085,10.478
|
||||
confirm,xiiotid__alpha0.25__seed3__support_weighted__beta1,done,11247.00,3.124,10.478
|
||||
confirm,xiiotid__alpha0.25__seed3__v_shrink__b1__lam0.5,done,10678.00,2.966,10.478
|
||||
confirm,xiiotid__alpha0.25__seed3__v_cap__b1__c4,done,10621.00,2.95,10.478
|
||||
confirm,xiiotid__alpha0.25__seed4__original_protean,done,11200.00,3.111,12.754
|
||||
confirm,xiiotid__alpha0.25__seed4__support_weighted__beta0.5,done,11147.00,3.096,12.757
|
||||
confirm,xiiotid__alpha0.25__seed4__support_weighted__beta1,done,11529.00,3.203,12.758
|
||||
confirm,xiiotid__alpha0.25__seed4__v_shrink__b1__lam0.5,done,11448.00,3.18,12.758
|
||||
confirm,xiiotid__alpha0.25__seed4__v_cap__b1__c4,done,10168.00,2.824,12.757
|
||||
confirm,5gnidd__alpha0.5__seed3__original_protean,done,15875.00,4.41,9.043
|
||||
confirm,5gnidd__alpha0.5__seed3__support_weighted__beta0.5,done,16116.00,4.477,9.067
|
||||
confirm,5gnidd__alpha0.5__seed3__support_weighted__beta1,done,16782.00,4.662,9.041
|
||||
confirm,5gnidd__alpha0.5__seed3__v_shrink__b1__lam0.5,done,16459.00,4.572,9.061
|
||||
confirm,5gnidd__alpha0.5__seed3__v_cap__b1__c4,done,17023.00,4.729,9.048
|
||||
confirm,5gnidd__alpha0.5__seed4__original_protean,done,17324.00,4.812,11.117
|
||||
confirm,5gnidd__alpha0.5__seed4__support_weighted__beta0.5,done,17181.00,4.772,11.156
|
||||
confirm,5gnidd__alpha0.5__seed4__support_weighted__beta1,done,17582.00,4.884,11.129
|
||||
confirm,5gnidd__alpha0.5__seed4__v_shrink__b1__lam0.5,done,17234.00,4.787,11.147
|
||||
confirm,5gnidd__alpha0.5__seed4__v_cap__b1__c4,done,16415.00,4.56,11.138
|
||||
|
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
# exploration_v2 driver entry point.
|
||||
#
|
||||
# Holds an exclusive lock so two drivers can never run at once. The actual
|
||||
# scheduler and heartbeat live in scripts/pool_driver.py. This script is safe
|
||||
# to re-invoke; resume.sh does exactly that.
|
||||
set -uo pipefail
|
||||
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$HERE/.." && pwd)"
|
||||
PY="$REPO_ROOT/.venv/bin/python"
|
||||
|
||||
export OMP_NUM_THREADS=1
|
||||
export MKL_NUM_THREADS=1
|
||||
export OPENBLAS_NUM_THREADS=1
|
||||
export NUMEXPR_NUM_THREADS=1
|
||||
export VECLIB_MAXIMUM_THREADS=1
|
||||
export PYTHONDONTWRITEBYTECODE=1
|
||||
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
|
||||
export DBUS_SESSION_BUS_ADDRESS="${DBUS_SESSION_BUS_ADDRESS:-unix:path=/run/user/$(id -u)/bus}"
|
||||
|
||||
mkdir -p "$HERE/logs"
|
||||
exec 9>"$HERE/driver.lock"
|
||||
if ! flock -n 9; then
|
||||
echo "[exploration_v2] another driver already holds driver.lock; exiting" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cd "$REPO_ROOT" || exit 3
|
||||
exec "$PY" "$HERE/scripts/pool_driver.py" "$@"
|
||||
@@ -0,0 +1,154 @@
|
||||
{
|
||||
"algorithm": "per_class_dirichlet_multinomial",
|
||||
"alpha": 0.5,
|
||||
"benign_class": "Benign",
|
||||
"class_names": [
|
||||
"Benign",
|
||||
"HTTPFlood",
|
||||
"ICMPFlood",
|
||||
"SYNFlood",
|
||||
"SYNScan",
|
||||
"SlowrateDoS",
|
||||
"TCPConnectScan",
|
||||
"UDPFlood",
|
||||
"UDPScan"
|
||||
],
|
||||
"config_hash": null,
|
||||
"created_utc": "2026-10-30T04:32:10Z",
|
||||
"dataset": "5gnidd",
|
||||
"dataset_name": "5G-NIDD",
|
||||
"manifest_version": "1",
|
||||
"num_classes": 9,
|
||||
"num_clients": 10,
|
||||
"num_train": 851123,
|
||||
"partition_hash": "0739f15c51fe4fa2250f717e8f52548706cb7093581447cd43a4b2364f6ec058",
|
||||
"preprocessing_hash": "60b5682b39184fd7d24e117430a00c160c5c7e95d1bc1fcaa99745108f514d81",
|
||||
"python": "3.12.3",
|
||||
"rng_seed": 2052809991,
|
||||
"seed": 3,
|
||||
"split": {
|
||||
"hash": "178e69cfacc40a1651246d0c33a26d16f76c8e19254d033c8c04cbbfbb86246a",
|
||||
"seed": 3,
|
||||
"sizes": {
|
||||
"test": 243177,
|
||||
"train": 851123,
|
||||
"validation": 121589
|
||||
},
|
||||
"strategy": "stratified_by_class",
|
||||
"test_fraction": 0.2,
|
||||
"train_fraction": 0.7,
|
||||
"validation_fraction": 0.1
|
||||
},
|
||||
"support": [
|
||||
[
|
||||
12367,
|
||||
24330,
|
||||
109,
|
||||
732,
|
||||
1299,
|
||||
2036,
|
||||
261,
|
||||
107583,
|
||||
129
|
||||
],
|
||||
[
|
||||
86013,
|
||||
9922,
|
||||
8,
|
||||
104,
|
||||
31,
|
||||
3166,
|
||||
1928,
|
||||
6739,
|
||||
5
|
||||
],
|
||||
[
|
||||
112226,
|
||||
6136,
|
||||
97,
|
||||
152,
|
||||
143,
|
||||
28,
|
||||
966,
|
||||
13880,
|
||||
301
|
||||
],
|
||||
[
|
||||
7322,
|
||||
29013,
|
||||
115,
|
||||
213,
|
||||
9592,
|
||||
159,
|
||||
373,
|
||||
2354,
|
||||
503
|
||||
],
|
||||
[
|
||||
28752,
|
||||
497,
|
||||
15,
|
||||
1688,
|
||||
71,
|
||||
19630,
|
||||
0,
|
||||
607,
|
||||
67
|
||||
],
|
||||
[
|
||||
11126,
|
||||
366,
|
||||
37,
|
||||
786,
|
||||
519,
|
||||
1272,
|
||||
140,
|
||||
84223,
|
||||
1613
|
||||
],
|
||||
[
|
||||
7958,
|
||||
249,
|
||||
40,
|
||||
912,
|
||||
93,
|
||||
801,
|
||||
3851,
|
||||
45015,
|
||||
8048
|
||||
],
|
||||
[
|
||||
64584,
|
||||
25,
|
||||
1,
|
||||
77,
|
||||
2281,
|
||||
20803,
|
||||
7,
|
||||
12615,
|
||||
17
|
||||
],
|
||||
[
|
||||
2496,
|
||||
14929,
|
||||
303,
|
||||
1582,
|
||||
1,
|
||||
2192,
|
||||
2455,
|
||||
189,
|
||||
234
|
||||
],
|
||||
[
|
||||
1571,
|
||||
13102,
|
||||
83,
|
||||
559,
|
||||
0,
|
||||
1100,
|
||||
4056,
|
||||
46933,
|
||||
217
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
{
|
||||
"algorithm": "per_class_dirichlet_multinomial",
|
||||
"alpha": 0.5,
|
||||
"benign_class": "Benign",
|
||||
"class_names": [
|
||||
"Benign",
|
||||
"HTTPFlood",
|
||||
"ICMPFlood",
|
||||
"SYNFlood",
|
||||
"SYNScan",
|
||||
"SlowrateDoS",
|
||||
"TCPConnectScan",
|
||||
"UDPFlood",
|
||||
"UDPScan"
|
||||
],
|
||||
"config_hash": null,
|
||||
"created_utc": "2026-10-30T04:32:41Z",
|
||||
"dataset": "5gnidd",
|
||||
"dataset_name": "5G-NIDD",
|
||||
"manifest_version": "1",
|
||||
"num_classes": 9,
|
||||
"num_clients": 10,
|
||||
"num_train": 851123,
|
||||
"partition_hash": "21a507d9d94f31154c5fb0c6833344738d1a137c78950f5284dec26d727e983a",
|
||||
"preprocessing_hash": "ffb7b2a1adb6cf8a292ea6e88dca574b44446da2b3ae18f690ae6fc59699e23d",
|
||||
"python": "3.12.3",
|
||||
"rng_seed": 1792011051,
|
||||
"seed": 4,
|
||||
"split": {
|
||||
"hash": "0b80242a3ac045217b73a89e5a7d03cb61abacefcc050e11b93ac83c831479ce",
|
||||
"seed": 4,
|
||||
"sizes": {
|
||||
"test": 243177,
|
||||
"train": 851123,
|
||||
"validation": 121589
|
||||
},
|
||||
"strategy": "stratified_by_class",
|
||||
"test_fraction": 0.2,
|
||||
"train_fraction": 0.7,
|
||||
"validation_fraction": 0.1
|
||||
},
|
||||
"support": [
|
||||
[
|
||||
159078,
|
||||
11071,
|
||||
39,
|
||||
936,
|
||||
8239,
|
||||
1050,
|
||||
33,
|
||||
15599,
|
||||
241
|
||||
],
|
||||
[
|
||||
15658,
|
||||
27988,
|
||||
318,
|
||||
7,
|
||||
674,
|
||||
7,
|
||||
5229,
|
||||
6152,
|
||||
93
|
||||
],
|
||||
[
|
||||
5874,
|
||||
2211,
|
||||
0,
|
||||
2113,
|
||||
893,
|
||||
1049,
|
||||
490,
|
||||
13122,
|
||||
131
|
||||
],
|
||||
[
|
||||
76962,
|
||||
851,
|
||||
10,
|
||||
26,
|
||||
1223,
|
||||
7546,
|
||||
846,
|
||||
57683,
|
||||
3055
|
||||
],
|
||||
[
|
||||
3588,
|
||||
47186,
|
||||
243,
|
||||
26,
|
||||
930,
|
||||
11733,
|
||||
1121,
|
||||
22035,
|
||||
1898
|
||||
],
|
||||
[
|
||||
26897,
|
||||
235,
|
||||
60,
|
||||
2927,
|
||||
181,
|
||||
263,
|
||||
2914,
|
||||
58429,
|
||||
2934
|
||||
],
|
||||
[
|
||||
143,
|
||||
5129,
|
||||
112,
|
||||
237,
|
||||
45,
|
||||
5427,
|
||||
36,
|
||||
7654,
|
||||
1444
|
||||
],
|
||||
[
|
||||
30083,
|
||||
3124,
|
||||
10,
|
||||
8,
|
||||
79,
|
||||
357,
|
||||
1910,
|
||||
111407,
|
||||
0
|
||||
],
|
||||
[
|
||||
405,
|
||||
4,
|
||||
5,
|
||||
413,
|
||||
1110,
|
||||
1483,
|
||||
1,
|
||||
14987,
|
||||
1323
|
||||
],
|
||||
[
|
||||
15727,
|
||||
770,
|
||||
11,
|
||||
112,
|
||||
656,
|
||||
22272,
|
||||
1457,
|
||||
13070,
|
||||
15
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
{
|
||||
"algorithm": "per_class_dirichlet_multinomial",
|
||||
"alpha": 0.25,
|
||||
"benign_class": "Normal",
|
||||
"class_names": [
|
||||
"C&C",
|
||||
"Exfiltration",
|
||||
"Exploitation",
|
||||
"Lateral_movement",
|
||||
"Normal",
|
||||
"RDOS",
|
||||
"Reconnaissance",
|
||||
"Tampering",
|
||||
"Weaponization"
|
||||
],
|
||||
"config_hash": null,
|
||||
"created_utc": "2026-10-30T04:00:15Z",
|
||||
"dataset": "xiiotid",
|
||||
"dataset_name": "X-IIoTID",
|
||||
"manifest_version": "1",
|
||||
"num_classes": 9,
|
||||
"num_clients": 10,
|
||||
"num_train": 569909,
|
||||
"partition_hash": "85a8625b81d3624dec9e5322979e2f1547f330c60d5e822e32c12177195ed602",
|
||||
"preprocessing_hash": "e22db95e5109bfa02701d8ce450453a7c8f7e408c94e81dfe2b95ef4ab2a441f",
|
||||
"python": "3.12.3",
|
||||
"rng_seed": 1031130567,
|
||||
"seed": 3,
|
||||
"split": {
|
||||
"hash": "8e66d08e71225567f8da977e5b927c476882c1d1ac768c1b490cdbc8de2945e9",
|
||||
"seed": 3,
|
||||
"sizes": {
|
||||
"test": 162831,
|
||||
"train": 569909,
|
||||
"validation": 81414
|
||||
},
|
||||
"strategy": "stratified_by_class",
|
||||
"test_fraction": 0.2,
|
||||
"train_fraction": 0.7,
|
||||
"validation_fraction": 0.1
|
||||
},
|
||||
"support": [
|
||||
[
|
||||
21,
|
||||
1003,
|
||||
0,
|
||||
7,
|
||||
2950,
|
||||
14,
|
||||
11735,
|
||||
0,
|
||||
342
|
||||
],
|
||||
[
|
||||
27,
|
||||
1029,
|
||||
7,
|
||||
199,
|
||||
549,
|
||||
1426,
|
||||
8567,
|
||||
370,
|
||||
1278
|
||||
],
|
||||
[
|
||||
1191,
|
||||
483,
|
||||
23,
|
||||
5147,
|
||||
17775,
|
||||
234,
|
||||
139,
|
||||
0,
|
||||
31
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
36,
|
||||
0,
|
||||
3006,
|
||||
58,
|
||||
12,
|
||||
12,
|
||||
1420
|
||||
],
|
||||
[
|
||||
15,
|
||||
18,
|
||||
39,
|
||||
2326,
|
||||
2692,
|
||||
58544,
|
||||
773,
|
||||
0,
|
||||
25866
|
||||
],
|
||||
[
|
||||
320,
|
||||
4958,
|
||||
0,
|
||||
31,
|
||||
966,
|
||||
18218,
|
||||
3006,
|
||||
949,
|
||||
8009
|
||||
],
|
||||
[
|
||||
0,
|
||||
2705,
|
||||
215,
|
||||
167,
|
||||
1157,
|
||||
1247,
|
||||
13942,
|
||||
2,
|
||||
347
|
||||
],
|
||||
[
|
||||
165,
|
||||
35,
|
||||
473,
|
||||
13685,
|
||||
111159,
|
||||
19011,
|
||||
15662,
|
||||
2013,
|
||||
120
|
||||
],
|
||||
[
|
||||
4,
|
||||
228,
|
||||
0,
|
||||
2,
|
||||
150706,
|
||||
122,
|
||||
35323,
|
||||
2,
|
||||
83
|
||||
],
|
||||
[
|
||||
261,
|
||||
5033,
|
||||
0,
|
||||
553,
|
||||
1817,
|
||||
9,
|
||||
2,
|
||||
238,
|
||||
7598
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
{
|
||||
"algorithm": "per_class_dirichlet_multinomial",
|
||||
"alpha": 0.25,
|
||||
"benign_class": "Normal",
|
||||
"class_names": [
|
||||
"C&C",
|
||||
"Exfiltration",
|
||||
"Exploitation",
|
||||
"Lateral_movement",
|
||||
"Normal",
|
||||
"RDOS",
|
||||
"Reconnaissance",
|
||||
"Tampering",
|
||||
"Weaponization"
|
||||
],
|
||||
"config_hash": null,
|
||||
"created_utc": "2026-10-30T04:31:39Z",
|
||||
"dataset": "xiiotid",
|
||||
"dataset_name": "X-IIoTID",
|
||||
"manifest_version": "1",
|
||||
"num_classes": 9,
|
||||
"num_clients": 10,
|
||||
"num_train": 569909,
|
||||
"partition_hash": "ff47f504d5b604935333ccbfddd060c18d44d672104e5455f86dcefe48315887",
|
||||
"preprocessing_hash": "4837f4ab5939fe7bf7f83168d915e67d570086d8534a521a9a9827f10aa41086",
|
||||
"python": "3.12.3",
|
||||
"rng_seed": 1148101028,
|
||||
"seed": 4,
|
||||
"split": {
|
||||
"hash": "5bc9100e5cbb4dfccf92e1b0fe64da544a2966c81d82dfab2efa2367173ca807",
|
||||
"seed": 4,
|
||||
"sizes": {
|
||||
"test": 162831,
|
||||
"train": 569909,
|
||||
"validation": 81414
|
||||
},
|
||||
"strategy": "stratified_by_class",
|
||||
"test_fraction": 0.2,
|
||||
"train_fraction": 0.7,
|
||||
"validation_fraction": 0.1
|
||||
},
|
||||
"support": [
|
||||
[
|
||||
1,
|
||||
109,
|
||||
667,
|
||||
156,
|
||||
193448,
|
||||
29952,
|
||||
1314,
|
||||
3,
|
||||
9802
|
||||
],
|
||||
[
|
||||
20,
|
||||
368,
|
||||
4,
|
||||
1852,
|
||||
13384,
|
||||
262,
|
||||
1102,
|
||||
42,
|
||||
4
|
||||
],
|
||||
[
|
||||
58,
|
||||
336,
|
||||
0,
|
||||
1331,
|
||||
0,
|
||||
218,
|
||||
32287,
|
||||
5,
|
||||
27
|
||||
],
|
||||
[
|
||||
0,
|
||||
7839,
|
||||
10,
|
||||
11,
|
||||
22325,
|
||||
619,
|
||||
12186,
|
||||
2959,
|
||||
7624
|
||||
],
|
||||
[
|
||||
413,
|
||||
94,
|
||||
4,
|
||||
9367,
|
||||
13997,
|
||||
0,
|
||||
1924,
|
||||
6,
|
||||
47
|
||||
],
|
||||
[
|
||||
238,
|
||||
5,
|
||||
3,
|
||||
0,
|
||||
1,
|
||||
24028,
|
||||
22974,
|
||||
62,
|
||||
5
|
||||
],
|
||||
[
|
||||
4,
|
||||
1,
|
||||
50,
|
||||
121,
|
||||
167,
|
||||
36163,
|
||||
14248,
|
||||
75,
|
||||
18287
|
||||
],
|
||||
[
|
||||
1110,
|
||||
508,
|
||||
47,
|
||||
6770,
|
||||
61,
|
||||
2656,
|
||||
25,
|
||||
88,
|
||||
147
|
||||
],
|
||||
[
|
||||
78,
|
||||
328,
|
||||
0,
|
||||
1112,
|
||||
42050,
|
||||
24,
|
||||
132,
|
||||
46,
|
||||
10
|
||||
],
|
||||
[
|
||||
82,
|
||||
5906,
|
||||
8,
|
||||
1397,
|
||||
7344,
|
||||
4961,
|
||||
2969,
|
||||
300,
|
||||
9141
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
run_id,dataset,alpha,seed,mode,beta,shrink,cap,minsup,part_dir,label,role
|
||||
xiiotid__alpha0.25__seed3__original_protean,xiiotid,0.25,3,original_protean,,,,,exploration_v2/partitions,original_protean,reference
|
||||
xiiotid__alpha0.25__seed3__support_weighted__beta0.5,xiiotid,0.25,3,support_weighted,0.5,,,,exploration_v2/partitions,support_weighted__beta0.5,reference
|
||||
xiiotid__alpha0.25__seed3__support_weighted__beta1,xiiotid,0.25,3,support_weighted,1,,,,exploration_v2/partitions,support_weighted__beta1,reference
|
||||
xiiotid__alpha0.25__seed3__v_shrink__b1__lam0.5,xiiotid,0.25,3,v_shrink,1.0,0.5,,,exploration_v2/partitions,v_shrink__b1__lam0.5,confirm_variant
|
||||
xiiotid__alpha0.25__seed3__v_cap__b1__c4,xiiotid,0.25,3,v_cap,1.0,,4,,exploration_v2/partitions,v_cap__b1__c4,confirm_variant
|
||||
xiiotid__alpha0.25__seed4__original_protean,xiiotid,0.25,4,original_protean,,,,,exploration_v2/partitions,original_protean,reference
|
||||
xiiotid__alpha0.25__seed4__support_weighted__beta0.5,xiiotid,0.25,4,support_weighted,0.5,,,,exploration_v2/partitions,support_weighted__beta0.5,reference
|
||||
xiiotid__alpha0.25__seed4__support_weighted__beta1,xiiotid,0.25,4,support_weighted,1,,,,exploration_v2/partitions,support_weighted__beta1,reference
|
||||
xiiotid__alpha0.25__seed4__v_shrink__b1__lam0.5,xiiotid,0.25,4,v_shrink,1.0,0.5,,,exploration_v2/partitions,v_shrink__b1__lam0.5,confirm_variant
|
||||
xiiotid__alpha0.25__seed4__v_cap__b1__c4,xiiotid,0.25,4,v_cap,1.0,,4,,exploration_v2/partitions,v_cap__b1__c4,confirm_variant
|
||||
5gnidd__alpha0.5__seed3__original_protean,5gnidd,0.5,3,original_protean,,,,,exploration_v2/partitions,original_protean,reference
|
||||
5gnidd__alpha0.5__seed3__support_weighted__beta0.5,5gnidd,0.5,3,support_weighted,0.5,,,,exploration_v2/partitions,support_weighted__beta0.5,reference
|
||||
5gnidd__alpha0.5__seed3__support_weighted__beta1,5gnidd,0.5,3,support_weighted,1,,,,exploration_v2/partitions,support_weighted__beta1,reference
|
||||
5gnidd__alpha0.5__seed3__v_shrink__b1__lam0.5,5gnidd,0.5,3,v_shrink,1.0,0.5,,,exploration_v2/partitions,v_shrink__b1__lam0.5,confirm_variant
|
||||
5gnidd__alpha0.5__seed3__v_cap__b1__c4,5gnidd,0.5,3,v_cap,1.0,,4,,exploration_v2/partitions,v_cap__b1__c4,confirm_variant
|
||||
5gnidd__alpha0.5__seed4__original_protean,5gnidd,0.5,4,original_protean,,,,,exploration_v2/partitions,original_protean,reference
|
||||
5gnidd__alpha0.5__seed4__support_weighted__beta0.5,5gnidd,0.5,4,support_weighted,0.5,,,,exploration_v2/partitions,support_weighted__beta0.5,reference
|
||||
5gnidd__alpha0.5__seed4__support_weighted__beta1,5gnidd,0.5,4,support_weighted,1,,,,exploration_v2/partitions,support_weighted__beta1,reference
|
||||
5gnidd__alpha0.5__seed4__v_shrink__b1__lam0.5,5gnidd,0.5,4,v_shrink,1.0,0.5,,,exploration_v2/partitions,v_shrink__b1__lam0.5,confirm_variant
|
||||
5gnidd__alpha0.5__seed4__v_cap__b1__c4,5gnidd,0.5,4,v_cap,1.0,,4,,exploration_v2/partitions,v_cap__b1__c4,confirm_variant
|
||||
|
@@ -0,0 +1,15 @@
|
||||
run_id,dataset,alpha,seed,mode,beta,shrink,cap,minsup,part_dir,label
|
||||
xiiotid__alpha0.25__seed0__original_protean,xiiotid,0.25,0,original_protean,,,,,artifacts/partitions,original_protean
|
||||
5gnidd__alpha0.5__seed0__original_protean,5gnidd,0.5,0,original_protean,,,,,artifacts/partitions,original_protean
|
||||
xiiotid__alpha0.25__seed0__v_beta__b1.5,xiiotid,0.25,0,v_beta,1.5,,,,artifacts/partitions,v_beta__b1.5
|
||||
xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5,xiiotid,0.25,0,v_shrink,1.0,0.5,,,artifacts/partitions,v_shrink__b1__lam0.5
|
||||
xiiotid__alpha0.25__seed0__v_cap__b1__c4,xiiotid,0.25,0,v_cap,1.0,,4,,artifacts/partitions,v_cap__b1__c4
|
||||
xiiotid__alpha0.25__seed0__v_cap__b1__c2,xiiotid,0.25,0,v_cap,1.0,,2,,artifacts/partitions,v_cap__b1__c2
|
||||
xiiotid__alpha0.25__seed0__v_minsup__t10,xiiotid,0.25,0,v_minsup,0.0,,,10,artifacts/partitions,v_minsup__t10
|
||||
xiiotid__alpha0.25__seed0__v_logweight,xiiotid,0.25,0,v_logweight,0.0,,,,artifacts/partitions,v_logweight
|
||||
5gnidd__alpha0.5__seed0__v_beta__b1.5,5gnidd,0.5,0,v_beta,1.5,,,,artifacts/partitions,v_beta__b1.5
|
||||
5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5,5gnidd,0.5,0,v_shrink,1.0,0.5,,,artifacts/partitions,v_shrink__b1__lam0.5
|
||||
5gnidd__alpha0.5__seed0__v_cap__b1__c4,5gnidd,0.5,0,v_cap,1.0,,4,,artifacts/partitions,v_cap__b1__c4
|
||||
5gnidd__alpha0.5__seed0__v_cap__b1__c2,5gnidd,0.5,0,v_cap,1.0,,2,,artifacts/partitions,v_cap__b1__c2
|
||||
5gnidd__alpha0.5__seed0__v_minsup__t10,5gnidd,0.5,0,v_minsup,0.0,,,10,artifacts/partitions,v_minsup__t10
|
||||
5gnidd__alpha0.5__seed0__v_logweight,5gnidd,0.5,0,v_logweight,0.0,,,,artifacts/partitions,v_logweight
|
||||
|
@@ -0,0 +1,513 @@
|
||||
{
|
||||
"generated_utc": "2026-10-31T05:03:55Z",
|
||||
"stage": "screening",
|
||||
"ranking_metric": "mean over S1,S2 of val_global_rare_f1(candidate) - val_global_rare_f1(original)",
|
||||
"secondary_metric": "same with val_rare_class_macro_f1_per_client_mean",
|
||||
"conditions": {
|
||||
"S1": {
|
||||
"dataset": "xiiotid",
|
||||
"alpha": 0.25
|
||||
},
|
||||
"S2": {
|
||||
"dataset": "5gnidd",
|
||||
"alpha": 0.5
|
||||
}
|
||||
},
|
||||
"screening_seed": 0,
|
||||
"baseline_source": {
|
||||
"S1": "in_environment_seed0",
|
||||
"S2": "in_environment_seed0"
|
||||
},
|
||||
"original": {
|
||||
"S1": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__original_protean",
|
||||
"source": "in_environment_seed0",
|
||||
"val_global_rare_f1": 0.6380388187784778,
|
||||
"val_global_rare_recall": 0.840600287361644,
|
||||
"val_global_macro_f1": 0.6716435746566032,
|
||||
"val_per_client_rare_f1": 0.6079725077419437,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"S2": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__original_protean",
|
||||
"source": "in_environment_seed0",
|
||||
"val_global_rare_f1": 0.8615257707605136,
|
||||
"val_global_rare_recall": 0.971733905845804,
|
||||
"val_global_macro_f1": 0.8292070866942571,
|
||||
"val_per_client_rare_f1": 0.7252793018231573,
|
||||
"val_sel_file_present": true
|
||||
}
|
||||
},
|
||||
"current_method_reference": {
|
||||
"S1": {
|
||||
"original": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__original_protean",
|
||||
"source": "in_environment_seed0",
|
||||
"val_global_rare_f1": 0.6380388187784778,
|
||||
"val_global_rare_recall": 0.840600287361644,
|
||||
"val_global_macro_f1": 0.6716435746566032,
|
||||
"val_per_client_rare_f1": 0.6079725077419437,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"best_beta_by_val_global": {
|
||||
"beta": 0.75,
|
||||
"val_global_rare_f1": 0.6690666806848056,
|
||||
"delta_vs_original": 0.03102786190632778
|
||||
},
|
||||
"best_beta_by_val_per_client": {
|
||||
"beta": 0.75,
|
||||
"val_per_client_rare_f1": 0.6564371328240081,
|
||||
"delta_vs_original": 0.048464625082064394
|
||||
},
|
||||
"all_betas": {
|
||||
"0": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__support_weighted__beta0",
|
||||
"source": "sweep_seed0_1thread",
|
||||
"val_global_rare_f1": 0.643275274917486,
|
||||
"val_global_rare_recall": 0.8414156040624469,
|
||||
"val_global_macro_f1": 0.6762678752194305,
|
||||
"val_per_client_rare_f1": 0.6151143983374613,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"0.25": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__support_weighted__beta0.25",
|
||||
"source": "sweep_seed0_1thread",
|
||||
"val_global_rare_f1": 0.6474224331223045,
|
||||
"val_global_rare_recall": 0.8369281236929922,
|
||||
"val_global_macro_f1": 0.6800358336787912,
|
||||
"val_per_client_rare_f1": 0.612295413922644,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"0.5": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__support_weighted__beta0.5",
|
||||
"source": "sweep_seed0_1thread",
|
||||
"val_global_rare_f1": 0.6328331530314106,
|
||||
"val_global_rare_recall": 0.8055422411499216,
|
||||
"val_global_macro_f1": 0.6670453405769549,
|
||||
"val_per_client_rare_f1": 0.5909962766172367,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"0.75": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__support_weighted__beta0.75",
|
||||
"source": "sweep_seed0_1thread",
|
||||
"val_global_rare_f1": 0.6690666806848056,
|
||||
"val_global_rare_recall": 0.8048039361797941,
|
||||
"val_global_macro_f1": 0.699686253411971,
|
||||
"val_per_client_rare_f1": 0.6564371328240081,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"1": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__support_weighted__beta1",
|
||||
"source": "sweep_seed0_1thread",
|
||||
"val_global_rare_f1": 0.5937608319568202,
|
||||
"val_global_rare_recall": 0.7156752311559107,
|
||||
"val_global_macro_f1": 0.6331165546843429,
|
||||
"val_per_client_rare_f1": 0.5797652799748645,
|
||||
"val_sel_file_present": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"S2": {
|
||||
"original": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__original_protean",
|
||||
"source": "in_environment_seed0",
|
||||
"val_global_rare_f1": 0.8615257707605136,
|
||||
"val_global_rare_recall": 0.971733905845804,
|
||||
"val_global_macro_f1": 0.8292070866942571,
|
||||
"val_per_client_rare_f1": 0.7252793018231573,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"best_beta_by_val_global": {
|
||||
"beta": 1.0,
|
||||
"val_global_rare_f1": 0.8762664919755059,
|
||||
"delta_vs_original": 0.014740721214992258
|
||||
},
|
||||
"best_beta_by_val_per_client": {
|
||||
"beta": 0.75,
|
||||
"val_per_client_rare_f1": 0.7719208198370514,
|
||||
"delta_vs_original": 0.046641518013894157
|
||||
},
|
||||
"all_betas": {
|
||||
"0": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__support_weighted__beta0",
|
||||
"source": "sweep_seed0_1thread",
|
||||
"val_global_rare_f1": 0.8676517373672202,
|
||||
"val_global_rare_recall": 0.971733905845804,
|
||||
"val_global_macro_f1": 0.8354514554793465,
|
||||
"val_per_client_rare_f1": 0.7394716750551001,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"0.25": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__support_weighted__beta0.25",
|
||||
"source": "sweep_seed0_1thread",
|
||||
"val_global_rare_f1": 0.8262070288650597,
|
||||
"val_global_rare_recall": 0.971733905845804,
|
||||
"val_global_macro_f1": 0.799036115730399,
|
||||
"val_per_client_rare_f1": 0.6579489943732403,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"0.5": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__support_weighted__beta0.5",
|
||||
"source": "sweep_seed0_1thread",
|
||||
"val_global_rare_f1": 0.8627083270087127,
|
||||
"val_global_rare_recall": 0.971733905845804,
|
||||
"val_global_macro_f1": 0.8363882297413696,
|
||||
"val_per_client_rare_f1": 0.7316622118992844,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"0.75": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__support_weighted__beta0.75",
|
||||
"source": "sweep_seed0_1thread",
|
||||
"val_global_rare_f1": 0.8751527301478877,
|
||||
"val_global_rare_recall": 0.971733905845804,
|
||||
"val_global_macro_f1": 0.8498739964533271,
|
||||
"val_per_client_rare_f1": 0.7719208198370514,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"1": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__support_weighted__beta1",
|
||||
"source": "sweep_seed0_1thread",
|
||||
"val_global_rare_f1": 0.8762664919755059,
|
||||
"val_global_rare_recall": 0.971733905845804,
|
||||
"val_global_macro_f1": 0.8461375258117143,
|
||||
"val_per_client_rare_f1": 0.7666551346534329,
|
||||
"val_sel_file_present": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"candidates": [
|
||||
{
|
||||
"label": "v_shrink__b1__lam0.5",
|
||||
"mode": "v_shrink",
|
||||
"params": {
|
||||
"beta": 1.0,
|
||||
"shrink_lambda": 0.5,
|
||||
"cap_factor": null,
|
||||
"min_support": null
|
||||
},
|
||||
"conditions": {
|
||||
"S1": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5",
|
||||
"val_global_rare_f1": 0.6771870761605789,
|
||||
"val_global_rare_recall": 0.8372489152448566,
|
||||
"val_global_macro_f1": 0.7085312157748022,
|
||||
"val_per_client_rare_f1": 0.6394200514807982,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"S2": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5",
|
||||
"val_global_rare_f1": 0.8757058802515706,
|
||||
"val_global_rare_recall": 0.971733905845804,
|
||||
"val_global_macro_f1": 0.839727653421119,
|
||||
"val_per_client_rare_f1": 0.7519195999208417,
|
||||
"val_sel_file_present": true
|
||||
}
|
||||
},
|
||||
"per_condition": {
|
||||
"S1": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5",
|
||||
"val_global_rare_f1": 0.6771870761605789,
|
||||
"baseline_val_global_rare_f1": 0.6380388187784778,
|
||||
"delta_vs_original": 0.03914825738210115,
|
||||
"val_per_client_rare_f1": 0.6394200514807982,
|
||||
"baseline_val_per_client_rare_f1": 0.6079725077419437,
|
||||
"delta_per_client_vs_original": 0.0314475437388545
|
||||
},
|
||||
"S2": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5",
|
||||
"val_global_rare_f1": 0.8757058802515706,
|
||||
"baseline_val_global_rare_f1": 0.8615257707605136,
|
||||
"delta_vs_original": 0.01418010949105697,
|
||||
"val_per_client_rare_f1": 0.7519195999208417,
|
||||
"baseline_val_per_client_rare_f1": 0.7252793018231573,
|
||||
"delta_per_client_vs_original": 0.026640298097684423
|
||||
}
|
||||
},
|
||||
"score": 0.02666418343657906,
|
||||
"min_condition_delta": 0.01418010949105697,
|
||||
"secondary_score_per_client": 0.02904392091826946,
|
||||
"rank": 1,
|
||||
"rank_secondary": 1
|
||||
},
|
||||
{
|
||||
"label": "v_cap__b1__c4",
|
||||
"mode": "v_cap",
|
||||
"params": {
|
||||
"beta": 1.0,
|
||||
"shrink_lambda": null,
|
||||
"cap_factor": 4.0,
|
||||
"min_support": null
|
||||
},
|
||||
"conditions": {
|
||||
"S1": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__v_cap__b1__c4",
|
||||
"val_global_rare_f1": 0.6415003766598666,
|
||||
"val_global_rare_recall": 0.7994428549956025,
|
||||
"val_global_macro_f1": 0.6751242688482385,
|
||||
"val_per_client_rare_f1": 0.6043797897480034,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"S2": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__v_cap__b1__c4",
|
||||
"val_global_rare_f1": 0.8708375305448125,
|
||||
"val_global_rare_recall": 0.9719002398444734,
|
||||
"val_global_macro_f1": 0.8324391611800375,
|
||||
"val_per_client_rare_f1": 0.7586411512962095,
|
||||
"val_sel_file_present": true
|
||||
}
|
||||
},
|
||||
"per_condition": {
|
||||
"S1": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__v_cap__b1__c4",
|
||||
"val_global_rare_f1": 0.6415003766598666,
|
||||
"baseline_val_global_rare_f1": 0.6380388187784778,
|
||||
"delta_vs_original": 0.0034615578813887993,
|
||||
"val_per_client_rare_f1": 0.6043797897480034,
|
||||
"baseline_val_per_client_rare_f1": 0.6079725077419437,
|
||||
"delta_per_client_vs_original": -0.003592717993940231
|
||||
},
|
||||
"S2": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__v_cap__b1__c4",
|
||||
"val_global_rare_f1": 0.8708375305448125,
|
||||
"baseline_val_global_rare_f1": 0.8615257707605136,
|
||||
"delta_vs_original": 0.009311759784298879,
|
||||
"val_per_client_rare_f1": 0.7586411512962095,
|
||||
"baseline_val_per_client_rare_f1": 0.7252793018231573,
|
||||
"delta_per_client_vs_original": 0.03336184947305221
|
||||
}
|
||||
},
|
||||
"score": 0.006386658832843839,
|
||||
"min_condition_delta": 0.0034615578813887993,
|
||||
"secondary_score_per_client": 0.014884565739555988,
|
||||
"rank": 2,
|
||||
"rank_secondary": 2
|
||||
},
|
||||
{
|
||||
"label": "v_cap__b1__c2",
|
||||
"mode": "v_cap",
|
||||
"params": {
|
||||
"beta": 1.0,
|
||||
"shrink_lambda": null,
|
||||
"cap_factor": 2.0,
|
||||
"min_support": null
|
||||
},
|
||||
"conditions": {
|
||||
"S1": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__v_cap__b1__c2",
|
||||
"val_global_rare_f1": 0.6324470193202425,
|
||||
"val_global_rare_recall": 0.8098457414207068,
|
||||
"val_global_macro_f1": 0.6670829111135634,
|
||||
"val_per_client_rare_f1": 0.5746261281359909,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"S2": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__v_cap__b1__c2",
|
||||
"val_global_rare_f1": 0.8622554197595921,
|
||||
"val_global_rare_recall": 0.9719002398444734,
|
||||
"val_global_macro_f1": 0.8250473485396072,
|
||||
"val_per_client_rare_f1": 0.7324286498183817,
|
||||
"val_sel_file_present": true
|
||||
}
|
||||
},
|
||||
"per_condition": {
|
||||
"S1": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__v_cap__b1__c2",
|
||||
"val_global_rare_f1": 0.6324470193202425,
|
||||
"baseline_val_global_rare_f1": 0.6380388187784778,
|
||||
"delta_vs_original": -0.0055917994582352915,
|
||||
"val_per_client_rare_f1": 0.5746261281359909,
|
||||
"baseline_val_per_client_rare_f1": 0.6079725077419437,
|
||||
"delta_per_client_vs_original": -0.03334637960595277
|
||||
},
|
||||
"S2": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__v_cap__b1__c2",
|
||||
"val_global_rare_f1": 0.8622554197595921,
|
||||
"baseline_val_global_rare_f1": 0.8615257707605136,
|
||||
"delta_vs_original": 0.0007296489990784583,
|
||||
"val_per_client_rare_f1": 0.7324286498183817,
|
||||
"baseline_val_per_client_rare_f1": 0.7252793018231573,
|
||||
"delta_per_client_vs_original": 0.0071493479952244865
|
||||
}
|
||||
},
|
||||
"score": -0.0024310752295784166,
|
||||
"min_condition_delta": -0.0055917994582352915,
|
||||
"secondary_score_per_client": -0.013098515805364142,
|
||||
"rank": 3,
|
||||
"rank_secondary": 3
|
||||
},
|
||||
{
|
||||
"label": "v_logweight",
|
||||
"mode": "v_logweight",
|
||||
"params": {
|
||||
"beta": 0.0,
|
||||
"shrink_lambda": null,
|
||||
"cap_factor": null,
|
||||
"min_support": null
|
||||
},
|
||||
"conditions": {
|
||||
"S1": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__v_logweight",
|
||||
"val_global_rare_f1": 0.6447702015221075,
|
||||
"val_global_rare_recall": 0.8413731264629913,
|
||||
"val_global_macro_f1": 0.6777965963838619,
|
||||
"val_per_client_rare_f1": 0.6126459310493659,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"S2": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__v_logweight",
|
||||
"val_global_rare_f1": 0.8269341324183733,
|
||||
"val_global_rare_recall": 0.971733905845804,
|
||||
"val_global_macro_f1": 0.8025209368110234,
|
||||
"val_per_client_rare_f1": 0.6604201812825267,
|
||||
"val_sel_file_present": true
|
||||
}
|
||||
},
|
||||
"per_condition": {
|
||||
"S1": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__v_logweight",
|
||||
"val_global_rare_f1": 0.6447702015221075,
|
||||
"baseline_val_global_rare_f1": 0.6380388187784778,
|
||||
"delta_vs_original": 0.006731382743629721,
|
||||
"val_per_client_rare_f1": 0.6126459310493659,
|
||||
"baseline_val_per_client_rare_f1": 0.6079725077419437,
|
||||
"delta_per_client_vs_original": 0.004673423307422264
|
||||
},
|
||||
"S2": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__v_logweight",
|
||||
"val_global_rare_f1": 0.8269341324183733,
|
||||
"baseline_val_global_rare_f1": 0.8615257707605136,
|
||||
"delta_vs_original": -0.034591638342140296,
|
||||
"val_per_client_rare_f1": 0.6604201812825267,
|
||||
"baseline_val_per_client_rare_f1": 0.7252793018231573,
|
||||
"delta_per_client_vs_original": -0.06485912054063059
|
||||
}
|
||||
},
|
||||
"score": -0.013930127799255287,
|
||||
"min_condition_delta": -0.034591638342140296,
|
||||
"secondary_score_per_client": -0.030092848616604162,
|
||||
"rank": 4,
|
||||
"rank_secondary": 5
|
||||
},
|
||||
{
|
||||
"label": "v_minsup__t10",
|
||||
"mode": "v_minsup",
|
||||
"params": {
|
||||
"beta": 0.0,
|
||||
"shrink_lambda": null,
|
||||
"cap_factor": null,
|
||||
"min_support": 10.0
|
||||
},
|
||||
"conditions": {
|
||||
"S1": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__v_minsup__t10",
|
||||
"val_global_rare_f1": 0.6214368387313907,
|
||||
"val_global_rare_recall": 0.8322773169160314,
|
||||
"val_global_macro_f1": 0.6563272217955932,
|
||||
"val_per_client_rare_f1": 0.581752384882787,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"S2": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__v_minsup__t10",
|
||||
"val_global_rare_f1": 0.8177717955235316,
|
||||
"val_global_rare_recall": 0.9716507803262696,
|
||||
"val_global_macro_f1": 0.8013311345491211,
|
||||
"val_per_client_rare_f1": 0.6513807368820619,
|
||||
"val_sel_file_present": true
|
||||
}
|
||||
},
|
||||
"per_condition": {
|
||||
"S1": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__v_minsup__t10",
|
||||
"val_global_rare_f1": 0.6214368387313907,
|
||||
"baseline_val_global_rare_f1": 0.6380388187784778,
|
||||
"delta_vs_original": -0.016601980047087128,
|
||||
"val_per_client_rare_f1": 0.581752384882787,
|
||||
"baseline_val_per_client_rare_f1": 0.6079725077419437,
|
||||
"delta_per_client_vs_original": -0.026220122859156647
|
||||
},
|
||||
"S2": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__v_minsup__t10",
|
||||
"val_global_rare_f1": 0.8177717955235316,
|
||||
"baseline_val_global_rare_f1": 0.8615257707605136,
|
||||
"delta_vs_original": -0.04375397523698199,
|
||||
"val_per_client_rare_f1": 0.6513807368820619,
|
||||
"baseline_val_per_client_rare_f1": 0.7252793018231573,
|
||||
"delta_per_client_vs_original": -0.07389856494109537
|
||||
}
|
||||
},
|
||||
"score": -0.03017797764203456,
|
||||
"min_condition_delta": -0.04375397523698199,
|
||||
"secondary_score_per_client": -0.05005934390012601,
|
||||
"rank": 5,
|
||||
"rank_secondary": 6
|
||||
},
|
||||
{
|
||||
"label": "v_beta__b1.5",
|
||||
"mode": "v_beta",
|
||||
"params": {
|
||||
"beta": 1.5,
|
||||
"shrink_lambda": null,
|
||||
"cap_factor": null,
|
||||
"min_support": null
|
||||
},
|
||||
"conditions": {
|
||||
"S1": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__v_beta__b1.5",
|
||||
"val_global_rare_f1": 0.5462339003533698,
|
||||
"val_global_rare_recall": 0.6920487487732283,
|
||||
"val_global_macro_f1": 0.5912778236542747,
|
||||
"val_per_client_rare_f1": 0.554598371814126,
|
||||
"val_sel_file_present": true
|
||||
},
|
||||
"S2": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__v_beta__b1.5",
|
||||
"val_global_rare_f1": 0.8563109585331589,
|
||||
"val_global_rare_recall": 0.971733905845804,
|
||||
"val_global_macro_f1": 0.8386791194607972,
|
||||
"val_per_client_rare_f1": 0.7263992771162339,
|
||||
"val_sel_file_present": true
|
||||
}
|
||||
},
|
||||
"per_condition": {
|
||||
"S1": {
|
||||
"run_id": "xiiotid__alpha0.25__seed0__v_beta__b1.5",
|
||||
"val_global_rare_f1": 0.5462339003533698,
|
||||
"baseline_val_global_rare_f1": 0.6380388187784778,
|
||||
"delta_vs_original": -0.09180491842510796,
|
||||
"val_per_client_rare_f1": 0.554598371814126,
|
||||
"baseline_val_per_client_rare_f1": 0.6079725077419437,
|
||||
"delta_per_client_vs_original": -0.0533741359278177
|
||||
},
|
||||
"S2": {
|
||||
"run_id": "5gnidd__alpha0.5__seed0__v_beta__b1.5",
|
||||
"val_global_rare_f1": 0.8563109585331589,
|
||||
"baseline_val_global_rare_f1": 0.8615257707605136,
|
||||
"delta_vs_original": -0.005214812227354759,
|
||||
"val_per_client_rare_f1": 0.7263992771162339,
|
||||
"baseline_val_per_client_rare_f1": 0.7252793018231573,
|
||||
"delta_per_client_vs_original": 0.0011199752930766138
|
||||
}
|
||||
},
|
||||
"score": -0.04850986532623136,
|
||||
"min_condition_delta": -0.09180491842510796,
|
||||
"secondary_score_per_client": -0.026127080317370543,
|
||||
"rank": 6,
|
||||
"rank_secondary": 4
|
||||
}
|
||||
],
|
||||
"secondary_ranking_order": [
|
||||
"v_shrink__b1__lam0.5",
|
||||
"v_cap__b1__c4",
|
||||
"v_cap__b1__c2",
|
||||
"v_beta__b1.5",
|
||||
"v_logweight",
|
||||
"v_minsup__t10"
|
||||
],
|
||||
"top2": [
|
||||
"v_shrink__b1__lam0.5",
|
||||
"v_cap__b1__c4"
|
||||
],
|
||||
"selection_margin_top1_minus_top2": 0.02027752460373522,
|
||||
"note": "Validation only. No test metric of any new run was read before this file was frozen."
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
f43ebc762d1512c5decfda51f31bef7f1d089a13156e8e3c3d7eae2982b054d3 ranking.json
|
||||
2026-10-31T05:03:55Z
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
# Resume the exploration_v2 driver in its dedicated tmux session.
|
||||
#
|
||||
# Safe to call repeatedly. Never kills a run that is already active; the
|
||||
# scheduler re-attaches to live systemd scopes by name.
|
||||
set -uo pipefail
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$HERE/.." && pwd)"
|
||||
SESSION="explore_v2"
|
||||
|
||||
if [ -f "$HERE/DONE" ]; then
|
||||
echo "[resume] DONE already exists; nothing to resume."
|
||||
cat "$HERE/DONE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Is a driver already holding the lock?
|
||||
if ! flock -n "$HERE/driver.lock" true 2>/dev/null; then
|
||||
echo "[resume] driver.lock is held: a driver is already running."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Also check for a live driver process (belt and braces).
|
||||
if pgrep -f '[p]ool_driver.py' >/dev/null 2>&1; then
|
||||
echo "[resume] pool_driver.py is already alive."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if tmux has-session -t "$SESSION" 2>/dev/null; then
|
||||
echo "[resume] respawning pane in existing tmux session $SESSION"
|
||||
tmux respawn-pane -k -t "$SESSION" "bash '$HERE/driver.sh'"
|
||||
else
|
||||
echo "[resume] creating tmux session $SESSION"
|
||||
tmux new-session -d -s "$SESSION" -c "$REPO_ROOT" "bash '$HERE/driver.sh'"
|
||||
fi
|
||||
tmux list-sessions 2>/dev/null | grep "^$SESSION" || true
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
# Inner command executed inside the systemd MemoryMax scope by run_one_v2.sh.
|
||||
# Usage: run_one_inner_v2.sh RUN_ID DATASET ALPHA SEED MODE BETA SHRINK CAP MINSUP PART_DIR LABEL
|
||||
set -uo pipefail
|
||||
|
||||
if [ "$#" -ne 11 ]; then
|
||||
echo "usage: run_one_inner_v2.sh RUN_ID DATASET ALPHA SEED MODE BETA SHRINK CAP MINSUP PART_DIR LABEL" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
RUN_ID="$1"; DATASET="$2"; ALPHA="$3"; SEED="$4"; MODE="$5"; BETA="$6"
|
||||
SHRINK="$7"; CAP="$8"; MINSUP="$9"; PART_DIR="${10}"; LABEL="${11}"
|
||||
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$HERE/.." && pwd)"
|
||||
RUN_DIR="$HERE/results/runs/$RUN_ID"
|
||||
|
||||
cd "$REPO_ROOT" || exit 3
|
||||
|
||||
EXTRA=(--variant-label "$LABEL")
|
||||
case "$MODE" in
|
||||
original_protean) ;;
|
||||
support_weighted) EXTRA+=(--beta "$BETA") ;;
|
||||
v_beta) EXTRA+=(--beta "$BETA") ;;
|
||||
v_shrink) EXTRA+=(--beta "$BETA" --shrink-lambda "$SHRINK") ;;
|
||||
v_cap) EXTRA+=(--beta "$BETA" --cap-factor "$CAP") ;;
|
||||
v_minsup) EXTRA+=(--beta "$BETA" --min-support "$MINSUP") ;;
|
||||
v_logweight) EXTRA+=(--beta "$BETA") ;;
|
||||
*) echo "unknown mode $MODE" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
exec "$REPO_ROOT/.venv/bin/python" "$HERE/scripts/thread1_launcher.py" \
|
||||
"$HERE/scripts/run_variant.py" \
|
||||
--dataset "$DATASET" \
|
||||
--alpha "$ALPHA" \
|
||||
--seed "$SEED" \
|
||||
--clients 10 \
|
||||
--rounds 10 \
|
||||
--local-epochs 3 \
|
||||
--batch-size 256 \
|
||||
--lr 0.001 \
|
||||
--mu 0.1 \
|
||||
--lam 1.0 \
|
||||
--aggregation-mode "$MODE" \
|
||||
"${EXTRA[@]}" \
|
||||
--partitions-dir "$PART_DIR" \
|
||||
--results-dir "$RUN_DIR/results" \
|
||||
--analysis-dir "$RUN_DIR/analysis" \
|
||||
--processed-dir "$RUN_DIR/processed"
|
||||
Executable
+182
@@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env bash
|
||||
# One resumable exploration_v2 run.
|
||||
#
|
||||
# run_one_v2.sh RUN_ID DATASET ALPHA SEED MODE BETA SHRINK CAP MINSUP PART_DIR LABEL
|
||||
#
|
||||
# Mirrors results/sweep/run_one.sh:
|
||||
# * one process, one thread (env pinned here and in thread1_launcher.py)
|
||||
# * one systemd user scope with MemoryMax=11G (xiiotid) / 15G (5gnidd)
|
||||
# and MemorySwapMax=0 (the sweep's per-dataset caps)
|
||||
# * logs under <run>/logs/, COMPLETE only after exit 0 and every primary
|
||||
# artifact exists and is non-empty
|
||||
# * summary.tsv upsert through run_record_v2.py
|
||||
# * .failed marker written on any non-zero exit so the driver can retry
|
||||
set -uo pipefail
|
||||
|
||||
if [ "$#" -ne 11 ]; then
|
||||
echo "usage: run_one_v2.sh RUN_ID DATASET ALPHA SEED MODE BETA SHRINK CAP MINSUP PART_DIR LABEL" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
RUN_ID="$1"; DATASET="$2"; ALPHA="$3"; SEED="$4"; MODE="$5"; BETA="$6"
|
||||
SHRINK="$7"; CAP="$8"; MINSUP="$9"; PART_DIR="${10}"; LABEL="${11}"
|
||||
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$HERE/.." && pwd)"
|
||||
PY="$REPO_ROOT/.venv/bin/python"
|
||||
|
||||
RUN_DIR="$HERE/results/runs/$RUN_ID"
|
||||
RESULTS_DIR="$RUN_DIR/results"
|
||||
ANALYSIS_DIR="$RUN_DIR/analysis"
|
||||
PROCESSED_DIR="$RUN_DIR/processed"
|
||||
LOG_DIR="$RUN_DIR/logs"
|
||||
|
||||
SUMMARY="$HERE/summary.csv"
|
||||
LOCK="$HERE/summary.lock"
|
||||
STOP_FILE="$HERE/STOP"
|
||||
|
||||
# Per-dataset systemd cgroup caps. 5G-NIDD keeps the sweep's 15G. X-IIoTID is
|
||||
# raised from the sweep's 11G to 13G after three cgroup OOM kills at 11G, while
|
||||
# two concurrent X-IIoTID processes still stay at 26G <= the 36G budget.
|
||||
case "$DATASET" in
|
||||
5gnidd) MEMORY_MAX="15G" ;;
|
||||
*) MEMORY_MAX="13G" ;;
|
||||
esac
|
||||
RUN_TIMEOUT_S="${EXPLORE_RUN_TIMEOUT_S:-43200}"
|
||||
|
||||
mkdir -p "$RESULTS_DIR" "$ANALYSIS_DIR" "$PROCESSED_DIR" "$LOG_DIR"
|
||||
|
||||
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
|
||||
export DBUS_SESSION_BUS_ADDRESS="${DBUS_SESSION_BUS_ADDRESS:-unix:path=/run/user/$(id -u)/bus}"
|
||||
export PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
utc() { date -u +%Y-%m-%dT%H:%M:%SZ; }
|
||||
log() { echo "[$(utc)] $*" >> "$LOG_DIR/run.log"; }
|
||||
|
||||
summary_row() {
|
||||
local status="$1" rc="$2" notes="${3:-}"
|
||||
local time_file=""
|
||||
[ -s "$LOG_DIR/time.txt" ] && time_file="$LOG_DIR/time.txt"
|
||||
"$PY" "$HERE/scripts/run_record_v2.py" record \
|
||||
--summary "$SUMMARY" --lock "$LOCK" \
|
||||
--run-name "$RUN_ID" --dataset "$DATASET" --alpha "$ALPHA" \
|
||||
--beta "$BETA" --seed "$SEED" --aggregation-mode "$MODE" \
|
||||
--status "$status" --exit-code "$rc" \
|
||||
--time-file "$time_file" --started "${STARTED:-}" --ended "$(utc)" \
|
||||
--run-dir "$RUN_DIR" --log-dir "$LOG_DIR" --notes "$notes" \
|
||||
|| log "WARNING: could not update summary.csv"
|
||||
}
|
||||
|
||||
primary_ok() {
|
||||
local p
|
||||
for p in \
|
||||
"$RESULTS_DIR/$RUN_ID/metadata.json" \
|
||||
"$RESULTS_DIR/$RUN_ID/history.json" \
|
||||
"$RESULTS_DIR/$RUN_ID/test_global_metrics.json" \
|
||||
"$RESULTS_DIR/$RUN_ID/test_confusion_matrix.json" \
|
||||
"$RESULTS_DIR/$RUN_ID/test_per_class.csv" \
|
||||
"$RESULTS_DIR/$RUN_ID/val_global_metrics.json" \
|
||||
"$RESULTS_DIR/$RUN_ID/val_selection.json" \
|
||||
"$RESULTS_DIR/$RUN_ID/per_client.csv" \
|
||||
"$RESULTS_DIR/$RUN_ID/val_per_client.csv" \
|
||||
"$RESULTS_DIR/$RUN_ID/train_support_Nij.csv" \
|
||||
"$RESULTS_DIR/$RUN_ID/characterization.csv" \
|
||||
"$RESULTS_DIR/$RUN_ID/rare_unseen.csv" \
|
||||
"$ANALYSIS_DIR/${RUN_ID}__prototype_snapshot.json" ; do
|
||||
[ -s "$p" ] || return 1
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
# ---- resumability -------------------------------------------------------
|
||||
if [ -f "$RUN_DIR/COMPLETE" ] && primary_ok; then
|
||||
log "SKIP: COMPLETE marker and all primary artifacts present"
|
||||
summary_row "skipped_complete" 0 "resumed: already complete"
|
||||
exit 0
|
||||
fi
|
||||
if [ -f "$RUN_DIR/COMPLETE" ]; then
|
||||
mv "$RUN_DIR/COMPLETE" "$RUN_DIR/COMPLETE.invalid.$(date -u +%Y%m%dT%H%M%SZ)"
|
||||
log "WARNING: moved invalid COMPLETE marker aside"
|
||||
fi
|
||||
|
||||
if [ -e "$STOP_FILE" ]; then
|
||||
log "STOP present: refusing to start $RUN_ID"
|
||||
summary_row "stopped" 0 "not started because exploration_v2/STOP exists"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ---- scope unit ---------------------------------------------------------
|
||||
UNIT="explorev2-$(printf '%s' "$RUN_ID" | sha1sum | cut -c1-12)"
|
||||
if systemctl --user is-active --quiet "$UNIT.scope" 2>/dev/null; then
|
||||
log "REFUSE: scope $UNIT already active"
|
||||
exit 0
|
||||
fi
|
||||
# A failed or OOM-killed transient scope keeps its unit name loaded, so a retry
|
||||
# with the same deterministic name is rejected by systemd-run. Unload it first
|
||||
# (and give systemd a moment) so retries can actually start.
|
||||
systemctl --user reset-failed "$UNIT.scope" >/dev/null 2>&1 || true
|
||||
sleep 1
|
||||
|
||||
STARTED="$(utc)"
|
||||
date -u +%s > "$LOG_DIR/start.epoch"
|
||||
echo "{\"run_id\": \"$RUN_ID\", \"unit\": \"$UNIT\", \"started_utc\": \"$STARTED\", \"pid\": $$}" > "$RUN_DIR/.running"
|
||||
|
||||
log "START dataset=$DATASET alpha=$ALPHA seed=$SEED mode=$MODE beta=$BETA label=$LABEL"
|
||||
log "command: systemd-run --user --scope -u $UNIT -p MemoryMax=$MEMORY_MAX -p MemorySwapMax=0 ..."
|
||||
|
||||
systemd-run --user --scope -q --unit="$UNIT" \
|
||||
-p "MemoryMax=$MEMORY_MAX" \
|
||||
-p "MemorySwapMax=0" \
|
||||
--setenv=OMP_NUM_THREADS=1 \
|
||||
--setenv=MKL_NUM_THREADS=1 \
|
||||
--setenv=OPENBLAS_NUM_THREADS=1 \
|
||||
--setenv=NUMEXPR_NUM_THREADS=1 \
|
||||
--setenv=VECLIB_MAXIMUM_THREADS=1 \
|
||||
--setenv=PYTHONDONTWRITEBYTECODE=1 \
|
||||
/usr/bin/time -v -o "$LOG_DIR/time.txt" \
|
||||
timeout --signal=TERM --kill-after=60s "$RUN_TIMEOUT_S" \
|
||||
bash "$HERE/run_one_inner_v2.sh" "$RUN_ID" "$DATASET" "$ALPHA" "$SEED" "$MODE" "$BETA" "$SHRINK" "$CAP" "$MINSUP" "$PART_DIR" "$LABEL" \
|
||||
> "$LOG_DIR/stdout.log" 2> "$LOG_DIR/stderr.log"
|
||||
RC=$?
|
||||
ENDED="$(utc)"
|
||||
date -u +%s > "$LOG_DIR/end.epoch"
|
||||
|
||||
# A systemd cgroup OOM kill can surface as 143 (the timeout process is
|
||||
# terminated with the rest of the cgroup) rather than 137. Query the transient
|
||||
# scope's Result so the driver's memory-kill throttle sees it correctly.
|
||||
SCOPE_RESULT="$(systemctl --user show -p Result --value "$UNIT.scope" 2>/dev/null || true)"
|
||||
if grep -q "Failed to start transient scope unit" "$LOG_DIR/stderr.log" 2>/dev/null; then
|
||||
log "scope did not start (unit-name collision); not treating as OOM"
|
||||
elif [ "$SCOPE_RESULT" = "oom-kill" ]; then
|
||||
log "scope result=oom-kill (exit was $RC); recording as memory kill 137"
|
||||
RC=137
|
||||
fi
|
||||
log "END exit_code=$RC"
|
||||
|
||||
rm -f "$RUN_DIR/.running"
|
||||
|
||||
# ---- completion marker / summary ---------------------------------------
|
||||
if [ "$RC" -eq 0 ] && primary_ok; then
|
||||
if "$PY" "$HERE/scripts/run_record_v2.py" marker \
|
||||
--run-dir "$RUN_DIR" --run-name "$RUN_ID" --dataset "$DATASET" \
|
||||
--alpha "$ALPHA" --beta "$BETA" --seed "$SEED" \
|
||||
--aggregation-mode "$MODE" --exit-code "$RC" \
|
||||
--time-file "$LOG_DIR/time.txt" --finished "$ENDED"; then
|
||||
summary_row "completed" "$RC" ""
|
||||
log "COMPLETE marker written"
|
||||
exit 0
|
||||
else
|
||||
summary_row "failed" "$RC" "artifacts missing; COMPLETE not written"
|
||||
printf '{"exit_code": %s, "reason": "artifacts_missing", "ended_utc": "%s"}\n' "$RC" "$ENDED" > "$RUN_DIR/.failed"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
note="exit=$RC"
|
||||
[ "$RC" -eq 124 ] && note="timeout after ${RUN_TIMEOUT_S}s"
|
||||
[ "$RC" -eq 137 ] && note="killed (137): likely MemoryMax=$MEMORY_MAX or OOM"
|
||||
[ "$RC" -eq 0 ] && note="exit=0 but one or more primary artifacts are missing/empty"
|
||||
summary_row "failed" "$RC" "$note"
|
||||
printf '{"exit_code": %s, "reason": "%s", "ended_utc": "%s"}\n' "$RC" "$note" "$ENDED" > "$RUN_DIR/.failed"
|
||||
log "ERROR: run not marked complete ($note)"
|
||||
exit 1
|
||||
@@ -0,0 +1,564 @@
|
||||
#!/usr/bin/env python
|
||||
"""Final analysis for exploration_v2 — all tables and REPORT_DATA.md.
|
||||
|
||||
Runs only after the ranking has been frozen and confirmation has finished (or
|
||||
the driver stopped). It may read test metrics of confirmation runs; it never
|
||||
uses them to re-rank or re-select anything.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import json
|
||||
import statistics as st
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
EXPL = REPO / "exploration_v2"
|
||||
RUNS = EXPL / "results" / "runs"
|
||||
OUT = EXPL / "analysis"
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
|
||||
def read_csv(p):
|
||||
if not Path(p).is_file():
|
||||
return []
|
||||
with Path(p).open(newline="", encoding="utf-8") as fh:
|
||||
return list(csv.DictReader(fh))
|
||||
|
||||
|
||||
def write_csv(name, rows):
|
||||
p = OUT / name
|
||||
if not rows:
|
||||
p.write_text("", encoding="utf-8")
|
||||
return
|
||||
with p.open("w", newline="", encoding="utf-8") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=list(rows[0].keys()))
|
||||
w.writeheader()
|
||||
w.writerows(rows)
|
||||
|
||||
|
||||
def jload(p):
|
||||
p = Path(p)
|
||||
if not p.is_file():
|
||||
return {}
|
||||
return json.loads(p.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def resolve(rid):
|
||||
"""Return the directory containing a run's metric files."""
|
||||
a = RUNS / rid / "results" / rid
|
||||
if (a / "val_global_metrics.json").is_file() or (a / "test_global_metrics.json").is_file():
|
||||
return a
|
||||
b = REPO / "results" / rid
|
||||
if (b / "val_global_metrics.json").is_file() or (b / "test_global_metrics.json").is_file():
|
||||
return b
|
||||
return None
|
||||
|
||||
|
||||
def metrics(rid):
|
||||
d = resolve(rid)
|
||||
if d is None:
|
||||
return None
|
||||
vg = jload(d / "val_global_metrics.json")
|
||||
vs = jload(d / "val_selection.json")
|
||||
tg = jload(d / "test_global_metrics.json")
|
||||
return {
|
||||
"val_global_rare_f1": vg.get("rare_class_macro_f1"),
|
||||
"val_global_rare_recall": vg.get("rare_class_recall"),
|
||||
"val_global_macro_f1": vg.get("macro_f1"),
|
||||
"val_per_client_rare_f1": vs.get("val_rare_class_macro_f1_per_client_mean"),
|
||||
"test_rare_f1": tg.get("rare_class_macro_f1"),
|
||||
"test_rare_recall": tg.get("rare_class_recall"),
|
||||
"test_macro_f1": tg.get("macro_f1"),
|
||||
}
|
||||
|
||||
|
||||
def summary_rows():
|
||||
rows = read_csv(EXPL / "summary.csv")
|
||||
return {r["config"]: r for r in rows}
|
||||
|
||||
|
||||
def pair_stats(diffs):
|
||||
diffs = [d for d in diffs if d is not None]
|
||||
if not diffs:
|
||||
return None, None, 0, 0
|
||||
return (st.fmean(diffs),
|
||||
st.stdev(diffs) if len(diffs) > 1 else None,
|
||||
sum(1 for d in diffs if d > 0),
|
||||
len(diffs))
|
||||
|
||||
|
||||
def main() -> int:
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
# Enforce the pre-registration gate: never analyse confirmation test
|
||||
# metrics unless the ranking was frozen first.
|
||||
rank_file = EXPL / "ranking.json"
|
||||
freeze_file = EXPL / "ranking.sha256"
|
||||
if not rank_file.is_file() or not freeze_file.is_file():
|
||||
raise SystemExit("ranking.json/ranking.sha256 missing: refusing to run "
|
||||
"the post-confirmation analysis")
|
||||
import hashlib
|
||||
recorded = freeze_file.read_text(encoding="utf-8").splitlines()[0].split()[0]
|
||||
actual = hashlib.sha256(rank_file.read_bytes()).hexdigest()
|
||||
if recorded != actual:
|
||||
raise SystemExit("ranking.json hash does not match the frozen record; "
|
||||
"refusing to re-rank or analyse")
|
||||
ranking = jload(rank_file)
|
||||
screen_q = read_csv(EXPL / "queue_screen.csv")
|
||||
confirm_q = read_csv(EXPL / "queue_confirm.csv")
|
||||
summ = summary_rows()
|
||||
top2 = ranking.get("top2", [])
|
||||
|
||||
# ---------------- inventory ----------------
|
||||
inv = []
|
||||
for phase, queue in (("screening", screen_q), ("confirm", confirm_q)):
|
||||
for r in queue:
|
||||
rid = r["run_id"]
|
||||
d = RUNS / rid
|
||||
if (d / "COMPLETE").is_file():
|
||||
status = "done"
|
||||
elif (d / ".failed").is_file():
|
||||
status = "failed"
|
||||
elif (d / ".running").is_file():
|
||||
status = "running"
|
||||
elif d.is_dir():
|
||||
status = "incomplete"
|
||||
else:
|
||||
status = "queued"
|
||||
s = summ.get(rid, {})
|
||||
inv.append({
|
||||
"phase": phase, "run_id": rid, "dataset": r["dataset"],
|
||||
"alpha": r["alpha"], "seed": r["seed"], "mode": r["mode"],
|
||||
"beta": r.get("beta", ""), "shrink_lambda": r.get("shrink", ""),
|
||||
"cap_factor": r.get("cap", ""), "min_support": r.get("minsup", ""),
|
||||
"label": r.get("label", ""), "status": status,
|
||||
"wall_s": s.get("wall_s", ""), "peak_rss_kb": s.get("peak_rss_kb", ""),
|
||||
"exit_code": s.get("exit_code", ""), "notes": s.get("notes", ""),
|
||||
})
|
||||
write_csv("run_inventory.csv", inv)
|
||||
|
||||
# ---------------- screening ranking ----------------
|
||||
screen_rows = []
|
||||
for c in ranking.get("candidates", []):
|
||||
row = {
|
||||
"rank": c["rank"], "rank_secondary": c.get("rank_secondary", ""),
|
||||
"label": c["label"], "mode": c["mode"],
|
||||
"beta": c["params"].get("beta"),
|
||||
"shrink_lambda": c["params"].get("shrink_lambda"),
|
||||
"cap_factor": c["params"].get("cap_factor"),
|
||||
"min_support": c["params"].get("min_support"),
|
||||
"score_mean_delta_val_global": c["score"],
|
||||
"min_condition_delta": c["min_condition_delta"],
|
||||
"secondary_mean_delta_val_per_client": c["secondary_score_per_client"],
|
||||
}
|
||||
for cid, per in c["per_condition"].items():
|
||||
row[f"{cid}_val_global"] = per["val_global_rare_f1"]
|
||||
row[f"{cid}_baseline"] = per["baseline_val_global_rare_f1"]
|
||||
row[f"{cid}_delta"] = per["delta_vs_original"]
|
||||
row[f"{cid}_val_per_client"] = per["val_per_client_rare_f1"]
|
||||
row[f"{cid}_delta_per_client"] = per["delta_per_client_vs_original"]
|
||||
screen_rows.append(row)
|
||||
write_csv("screening_ranking.csv", screen_rows)
|
||||
|
||||
# reference rows for the same conditions
|
||||
ref_rows = []
|
||||
for cid, ref in ranking.get("current_method_reference", {}).items():
|
||||
ref_rows.append({
|
||||
"condition": cid,
|
||||
"baseline_run": ref["original"]["run_id"],
|
||||
"baseline_val_global": ref["original"]["val_global_rare_f1"],
|
||||
"best_beta_by_val_global": ref["best_beta_by_val_global"]["beta"],
|
||||
"best_val_global": ref["best_beta_by_val_global"]["val_global_rare_f1"],
|
||||
"best_delta_global": ref["best_beta_by_val_global"]["delta_vs_original"],
|
||||
"best_beta_by_val_per_client": ref["best_beta_by_val_per_client"]["beta"],
|
||||
"best_val_per_client": ref["best_beta_by_val_per_client"]["val_per_client_rare_f1"],
|
||||
"best_delta_per_client": ref["best_beta_by_val_per_client"]["delta_vs_original"],
|
||||
})
|
||||
write_csv("screening_references.csv", ref_rows)
|
||||
|
||||
# ---------------- confirmation ----------------
|
||||
conditions = {"S1": ("xiiotid", 0.25), "S2": ("5gnidd", 0.5)}
|
||||
|
||||
def rid_for(ds, alpha, seed, label):
|
||||
return f"{ds}__alpha{alpha:g}__seed{seed}__{label}"
|
||||
|
||||
confirm_rows = []
|
||||
for ds, alpha in conditions.values():
|
||||
for seed in (3, 4):
|
||||
base_id = rid_for(ds, alpha, seed, "original_protean")
|
||||
base = metrics(base_id)
|
||||
b05 = metrics(rid_for(ds, alpha, seed, "support_weighted__beta0.5"))
|
||||
b1 = metrics(rid_for(ds, alpha, seed, "support_weighted__beta1"))
|
||||
if base is None:
|
||||
continue
|
||||
cur_candidates = [("original_protean", base),
|
||||
("support_weighted__beta0.5", b05),
|
||||
("support_weighted__beta1", b1)]
|
||||
cur_candidates = [(n, m) for n, m in cur_candidates
|
||||
if m is not None and m["val_global_rare_f1"] is not None]
|
||||
cur_name, cur_best = max(
|
||||
cur_candidates, key=lambda nm: nm[1]["val_global_rare_f1"])
|
||||
for label in top2 + ["support_weighted__beta0.5", "support_weighted__beta1"]:
|
||||
rid = rid_for(ds, alpha, seed, label)
|
||||
m = metrics(rid)
|
||||
if m is None:
|
||||
continue
|
||||
confirm_rows.append({
|
||||
"dataset": ds, "alpha": alpha, "seed": seed,
|
||||
"config": label, "run_id": rid,
|
||||
"val_global_rare_f1": m["val_global_rare_f1"],
|
||||
"val_per_client_rare_f1": m["val_per_client_rare_f1"],
|
||||
"test_rare_f1": m["test_rare_f1"],
|
||||
"test_rare_recall": m["test_rare_recall"],
|
||||
"baseline_val_global": base["val_global_rare_f1"],
|
||||
"baseline_test_rare_f1": base["test_rare_f1"],
|
||||
"delta_val_vs_original": (m["val_global_rare_f1"] - base["val_global_rare_f1"]),
|
||||
"delta_test_vs_original": (m["test_rare_f1"] - base["test_rare_f1"]),
|
||||
"delta_val_vs_beta1": ((m["val_global_rare_f1"] - b1["val_global_rare_f1"])
|
||||
if b1 and b1["val_global_rare_f1"] is not None else None),
|
||||
"delta_test_vs_beta1": ((m["test_rare_f1"] - b1["test_rare_f1"])
|
||||
if b1 and b1["test_rare_f1"] is not None else None),
|
||||
"delta_val_vs_beta05": ((m["val_global_rare_f1"] - b05["val_global_rare_f1"])
|
||||
if b05 and b05["val_global_rare_f1"] is not None else None),
|
||||
"delta_test_vs_beta05": ((m["test_rare_f1"] - b05["test_rare_f1"])
|
||||
if b05 and b05["test_rare_f1"] is not None else None),
|
||||
"current_best_config": cur_name,
|
||||
"current_best_val_global": cur_best["val_global_rare_f1"],
|
||||
"delta_val_vs_current_best": (m["val_global_rare_f1"]
|
||||
- cur_best["val_global_rare_f1"]),
|
||||
"delta_test_vs_current_best": ((m["test_rare_f1"] - cur_best["test_rare_f1"])
|
||||
if m["test_rare_f1"] is not None
|
||||
and cur_best["test_rare_f1"] is not None
|
||||
else None),
|
||||
})
|
||||
write_csv("confirm_paired.csv", confirm_rows)
|
||||
|
||||
summary = []
|
||||
for label in top2:
|
||||
rows = [r for r in confirm_rows if r["config"] == label]
|
||||
dv = [r["delta_val_vs_original"] for r in rows]
|
||||
dt = [r["delta_test_vs_original"] for r in rows]
|
||||
d1v = [r["delta_val_vs_beta1"] for r in rows]
|
||||
d1t = [r["delta_test_vs_beta1"] for r in rows]
|
||||
d05v = [r["delta_val_vs_beta05"] for r in rows]
|
||||
d05t = [r["delta_test_vs_beta05"] for r in rows]
|
||||
dcbv = [r["delta_val_vs_current_best"] for r in rows]
|
||||
dcbt = [r["delta_test_vs_current_best"] for r in rows]
|
||||
mcbv, scbv, poscbv, _ = pair_stats(dcbv)
|
||||
mcbt, scbt, poscbt, _ = pair_stats(dcbt)
|
||||
mv, sv, pos, n = pair_stats(dv)
|
||||
mt, stt, post, _ = pair_stats(dt)
|
||||
m1v, s1v, _, _ = pair_stats(d1v)
|
||||
m1t, s1t, _, _ = pair_stats(d1t)
|
||||
m05v, s05v, _, _ = pair_stats(d05v)
|
||||
m05t, s05t, _, _ = pair_stats(d05t)
|
||||
per_cond = {}
|
||||
for cid, (ds, alpha) in conditions.items():
|
||||
sub = [r for r in rows if r["dataset"] == ds and r["alpha"] == alpha]
|
||||
per_cond[cid] = [r["delta_val_vs_original"] for r in sub]
|
||||
improved = bool(mv is not None and mv > 0 and pos == n and n == 4)
|
||||
summary.append({
|
||||
"variant": label,
|
||||
"n_pairs": n,
|
||||
"mean_delta_val_vs_original": mv, "sd_delta_val_vs_original": sv,
|
||||
"positive_pairs_val_vs_original": pos,
|
||||
"mean_delta_test_vs_original": mt, "sd_delta_test_vs_original": stt,
|
||||
"positive_pairs_test_vs_original": post,
|
||||
"mean_delta_val_vs_beta1": m1v, "sd_delta_val_vs_beta1": s1v,
|
||||
"mean_delta_test_vs_beta1": m1t, "sd_delta_test_vs_beta1": s1t,
|
||||
"mean_delta_val_vs_beta05": m05v, "sd_delta_val_vs_beta05": s05v,
|
||||
"mean_delta_test_vs_beta05": m05t, "sd_delta_test_vs_beta05": s05t,
|
||||
"mean_delta_val_vs_current_best": mcbv,
|
||||
"sd_delta_val_vs_current_best": scbv,
|
||||
"positive_pairs_val_vs_current_best": poscbv,
|
||||
"mean_delta_test_vs_current_best": mcbt,
|
||||
"sd_delta_test_vs_current_best": scbt,
|
||||
"positive_pairs_test_vs_current_best": poscbt,
|
||||
"improved_vs_original_per_plan": improved,
|
||||
"S1_val_deltas": "|".join(f"{x:.6f}" for x in per_cond.get("S1", [])),
|
||||
"S2_val_deltas": "|".join(f"{x:.6f}" for x in per_cond.get("S2", [])),
|
||||
})
|
||||
write_csv("confirm_summary.csv", summary)
|
||||
|
||||
# reference configurations (beta1, beta05) summary over the same seeds
|
||||
ref_summary = []
|
||||
for label in ("support_weighted__beta0.5", "support_weighted__beta1"):
|
||||
rows = [r for r in confirm_rows if r["config"] == label]
|
||||
dv = [r["delta_val_vs_original"] for r in rows]
|
||||
dt = [r["delta_test_vs_original"] for r in rows]
|
||||
mv, sv, pos, n = pair_stats(dv)
|
||||
mt, stt, post, _ = pair_stats(dt)
|
||||
ref_summary.append({"config": label, "n_pairs": n,
|
||||
"mean_delta_val_vs_original": mv,
|
||||
"sd_delta_val_vs_original": sv,
|
||||
"positive_pairs_val": pos,
|
||||
"mean_delta_test_vs_original": mt,
|
||||
"sd_delta_test_vs_original": stt,
|
||||
"positive_pairs_test": post})
|
||||
write_csv("confirm_reference_summary.csv", ref_summary)
|
||||
|
||||
# ---------------- reference consistency (environment check) ----------
|
||||
ref_cons = []
|
||||
for cid, (ds, alpha) in conditions.items():
|
||||
base = f"{ds}__alpha{alpha:g}__seed0"
|
||||
new_id = f"{base}__original_protean"
|
||||
new_dir = RUNS / new_id / "results" / new_id
|
||||
new_val = (jload(new_dir / "val_global_metrics.json").get("rare_class_macro_f1")
|
||||
if (new_dir / "val_global_metrics.json").is_file()
|
||||
else None)
|
||||
old_id = new_id
|
||||
old_val = jload(REPO / "results" / old_id / "val_global_metrics.json").get(
|
||||
"rare_class_macro_f1")
|
||||
sweep_id = f"{base}__support_weighted__beta0"
|
||||
sweep_dir = REPO / "results" / "sweep" / "runs" / sweep_id / "results" / sweep_id
|
||||
sweep_val = (jload(sweep_dir / "val_global_metrics.json").get("rare_class_macro_f1")
|
||||
if (sweep_dir / "val_global_metrics.json").is_file() else None)
|
||||
ref_cons.append({
|
||||
"condition": cid, "dataset": ds, "alpha": alpha,
|
||||
"new_original_val_global": new_val,
|
||||
"restored_original_val_global": old_val,
|
||||
"sweep_beta0_val_global": sweep_val,
|
||||
"new_minus_restored": (new_val - old_val) if new_val is not None and old_val is not None else None,
|
||||
"new_minus_sweep_beta0": (new_val - sweep_val) if new_val is not None and sweep_val is not None else None,
|
||||
})
|
||||
write_csv("reference_consistency.csv", ref_cons)
|
||||
|
||||
# ---------------- wall time / memory ----------------
|
||||
wall = []
|
||||
for r in inv:
|
||||
wall.append({"phase": r["phase"], "run_id": r["run_id"],
|
||||
"status": r["status"], "wall_s": r["wall_s"],
|
||||
"wall_h": (round(float(r["wall_s"]) / 3600, 3)
|
||||
if r["wall_s"] not in ("", None) else None),
|
||||
"peak_rss_gib": (round(float(r["peak_rss_kb"]) / 1048576, 3)
|
||||
if r["peak_rss_kb"] not in ("", None) else None)})
|
||||
write_csv("walltime.csv", wall)
|
||||
|
||||
# ---------------- REPORT_DATA.md ----------------
|
||||
def fmt(x, nd=4):
|
||||
if x is None or x == "":
|
||||
return ""
|
||||
try:
|
||||
return f"{float(x):.{nd}f}"
|
||||
except Exception:
|
||||
return str(x)
|
||||
|
||||
lines = []
|
||||
lines.append("# exploration_v2 — report data\n")
|
||||
from datetime import datetime, timezone
|
||||
lines.append(f"Generated: {datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')}\n")
|
||||
lines.append("This file is generated by `exploration_v2/scripts/analyze_results.py`. "
|
||||
"All numbers come from files on disk. Missing rows mean a run did not "
|
||||
"produce the metric.\n")
|
||||
|
||||
lines.append("## Plan and ranking freeze\n")
|
||||
lines.append("| item | value |\n|---|---|\n")
|
||||
for name in ("PLAN.sha256", "ranking.sha256"):
|
||||
p = EXPL / name
|
||||
if p.is_file():
|
||||
content = p.read_text(encoding="utf-8").splitlines()
|
||||
lines.append(f"| `{name}` | `{content[0] if content else ''}`"
|
||||
f"{(' at ' + content[1]) if len(content) > 1 else ''} |\n")
|
||||
lines.append("\n")
|
||||
|
||||
lines.append("## Screening ranking (validation only)\n")
|
||||
if ranking:
|
||||
lines.append(f"Top-1 minus top-2 validation score (selection margin): "
|
||||
f"{fmt(ranking.get('selection_margin_top1_minus_top2'), 6)} "
|
||||
f"(top2 = {ranking.get('top2')}).\n\n")
|
||||
lines.append("Score = mean over S1,S2 of the paired validation difference in "
|
||||
"global rare-class macro-F1 versus the original baseline.\n\n")
|
||||
lines.append("| rank | variant | β | λ | cap | min N | score | min cond Δ | "
|
||||
"S1 Δ | S2 Δ | secondary rank |\n|---|---|---|---|---|---|---|---|---|---|---|\n")
|
||||
for r in screen_rows:
|
||||
lines.append(f"| {r['rank']} | `{r['label']}` | {fmt(r['beta'],2)} | "
|
||||
f"{fmt(r['shrink_lambda'],2)} | {fmt(r['cap_factor'],1)} | "
|
||||
f"{fmt(r['min_support'],0)} | {fmt(r['score_mean_delta_val_global'])} | "
|
||||
f"{fmt(r['min_condition_delta'])} | {fmt(r.get('S1_delta'))} | "
|
||||
f"{fmt(r.get('S2_delta'))} | {r['rank_secondary']} |\n")
|
||||
lines.append("\n")
|
||||
|
||||
lines.append("## Confirmatory results (per seed)\n")
|
||||
lines.append("| dataset | α | seed | config | val rare-F1 | test rare-F1 | "
|
||||
"Δval vs orig | Δtest vs orig | Δval vs β=1 | Δtest vs β=1 |\n"
|
||||
"|---|---|---|---|---|---|---|---|---|---|\n")
|
||||
for r in confirm_rows:
|
||||
lines.append(f"| {r['dataset']} | {fmt(r['alpha'],2)} | {r['seed']} | "
|
||||
f"`{r['config']}` | {fmt(r['val_global_rare_f1'])} | "
|
||||
f"{fmt(r['test_rare_f1'])} | {fmt(r['delta_val_vs_original'])} | "
|
||||
f"{fmt(r['delta_test_vs_original'])} | {fmt(r['delta_val_vs_beta1'])} | "
|
||||
f"{fmt(r['delta_test_vs_beta1'])} |\n")
|
||||
lines.append("\n")
|
||||
|
||||
lines.append("## Confirmatory summary\n")
|
||||
lines.append("| variant | mean Δval vs orig | sd | positive/4 | mean Δtest vs orig | "
|
||||
"sd | mean Δval vs β=1 | mean Δtest vs β=1 | mean Δval vs current best | "
|
||||
"mean Δtest vs current best | improved per plan |\n"
|
||||
"|---|---|---|---|---|---|---|---|---|\n")
|
||||
for r in summary:
|
||||
lines.append(f"| `{r['variant']}` | {fmt(r['mean_delta_val_vs_original'])} | "
|
||||
f"{fmt(r['sd_delta_val_vs_original'])} | "
|
||||
f"{r['positive_pairs_val_vs_original']}/{r['n_pairs']} | "
|
||||
f"{fmt(r['mean_delta_test_vs_original'])} | "
|
||||
f"{fmt(r['sd_delta_test_vs_original'])} | "
|
||||
f"{fmt(r['mean_delta_val_vs_beta1'])} | "
|
||||
f"{fmt(r['mean_delta_test_vs_beta1'])} | "
|
||||
f"{fmt(r.get('mean_delta_val_vs_current_best'))} | "
|
||||
f"{fmt(r.get('mean_delta_test_vs_current_best'))} | "
|
||||
f"{r['improved_vs_original_per_plan']} |\n")
|
||||
lines.append("\n")
|
||||
|
||||
lines.append("## Reference configurations on the confirmation seeds\n")
|
||||
lines.append("| config | mean Δval vs orig | sd | positive | mean Δtest vs orig | sd | positive |\n"
|
||||
"|---|---|---|---|---|---|---|\n")
|
||||
for r in ref_summary:
|
||||
lines.append(f"| `{r['config']}` | {fmt(r['mean_delta_val_vs_original'])} | "
|
||||
f"{fmt(r['sd_delta_val_vs_original'])} | {r['positive_pairs_val']} | "
|
||||
f"{fmt(r['mean_delta_test_vs_original'])} | "
|
||||
f"{fmt(r['sd_delta_test_vs_original'])} | {r['positive_pairs_test']} |\n")
|
||||
lines.append("\n")
|
||||
|
||||
lines.append("## Reference consistency (environment check)\n")
|
||||
lines.append("| condition | new original val | restored original val | sweep β=0 val | "
|
||||
"new − restored | new − sweep β=0 |\n|---|---|---|---|---|---|\n")
|
||||
for r in ref_cons:
|
||||
lines.append(f"| {r['condition']} | {fmt(r['new_original_val_global'])} | "
|
||||
f"{fmt(r['restored_original_val_global'])} | "
|
||||
f"{fmt(r['sweep_beta0_val_global'])} | "
|
||||
f"{fmt(r['new_minus_restored'])} | "
|
||||
f"{fmt(r['new_minus_sweep_beta0'])} |\n")
|
||||
lines.append("\n")
|
||||
|
||||
lines.append("## Wall time and memory (new runs)\n")
|
||||
lines.append("| phase | run | status | wall h | peak GiB |\n|---|---|---|---|---|\n")
|
||||
for r in wall:
|
||||
lines.append(f"| {r['phase']} | `{r['run_id']}` | {r['status']} | "
|
||||
f"{fmt(r['wall_h'],2)} | {fmt(r['peak_rss_gib'],2)} |\n")
|
||||
lines.append("\n")
|
||||
|
||||
lines.append("## Failed or missing runs\n")
|
||||
bad = [r for r in inv if r["status"] in ("failed", "incomplete", "queued")]
|
||||
if not bad:
|
||||
lines.append("None.\n")
|
||||
else:
|
||||
lines.append("| phase | run | status | exit | notes |\n|---|---|---|---|---|\n")
|
||||
for r in bad:
|
||||
lines.append(f"| {r['phase']} | `{r['run_id']}` | {r['status']} | "
|
||||
f"{r['exit_code']} | {r['notes']} |\n")
|
||||
lines.append("\n")
|
||||
|
||||
(EXPL / "REPORT_DATA.md").write_text("".join(lines), encoding="utf-8")
|
||||
|
||||
# ---- inject the same tables into REPORT.md between the markers -------
|
||||
def f(x, nd=4):
|
||||
if x in (None, ""):
|
||||
return ""
|
||||
try:
|
||||
return f"{float(x):.{nd}f}"
|
||||
except Exception:
|
||||
return str(x)
|
||||
|
||||
auto = []
|
||||
auto.append("## 5. Results of the new runs\n\n")
|
||||
auto.append("### 5.1 Screening ranking (validation only)\n\n")
|
||||
if ranking:
|
||||
auto.append(f"Top-1 minus top-2 validation score (selection margin): "
|
||||
f"{f(ranking.get('selection_margin_top1_minus_top2'), 6)} "
|
||||
f"(top2 = {ranking.get('top2')}).\n\n")
|
||||
auto.append("Score = mean over S1,S2 of the paired validation difference in "
|
||||
"global rare-class macro-F1 versus the in-environment original "
|
||||
"baseline. `rank_secondary` uses the deployed per-client-mean "
|
||||
"metric.\n\n")
|
||||
auto.append("| rank | variant | β | λ | cap | min N | score | min cond Δ | "
|
||||
"S1 Δ | S2 Δ | rank_secondary |\n|---|---|---|---|---|---|---|---|---|---|\n")
|
||||
for r in read_csv(OUT / "screening_ranking.csv"):
|
||||
auto.append(f"| {r['rank']} | `{r['label']}` | {f(r['beta'],2)} | "
|
||||
f"{f(r['shrink_lambda'],2)} | {f(r['cap_factor'],1)} | "
|
||||
f"{f(r['min_support'],0)} | {f(r['score_mean_delta_val_global'])} | "
|
||||
f"{f(r['min_condition_delta'])} | {f(r.get('S1_delta'))} | "
|
||||
f"{f(r.get('S2_delta'))} | {r['rank_secondary']} |\n")
|
||||
auto.append("\n")
|
||||
auto.append("### 5.2 Confirmatory runs, per seed\n\n")
|
||||
auto.append("| dataset | α | seed | config | val rare-F1 | test rare-F1 | "
|
||||
"Δval vs orig | Δtest vs orig | Δval vs β=1 | Δtest vs β=1 |\n"
|
||||
"|---|---|---|---|---|---|---|---|---|---|\n")
|
||||
for r in read_csv(OUT / "confirm_paired.csv"):
|
||||
auto.append(f"| {r['dataset']} | {f(r['alpha'],2)} | {r['seed']} | "
|
||||
f"`{r['config']}` | {f(r['val_global_rare_f1'])} | "
|
||||
f"{f(r['test_rare_f1'])} | {f(r['delta_val_vs_original'])} | "
|
||||
f"{f(r['delta_test_vs_original'])} | {f(r['delta_val_vs_beta1'])} | "
|
||||
f"{f(r['delta_test_vs_beta1'])} |\n")
|
||||
auto.append("\n")
|
||||
auto.append("### 5.3 Confirmatory summary\n\n")
|
||||
auto.append("A variant “improves” under the pre-registered rule only if the "
|
||||
"mean validation difference over the four pairs is positive **and** "
|
||||
"all four are positive.\n\n")
|
||||
auto.append("| variant | mean Δval vs orig | sd | positive/4 | mean Δtest vs orig | "
|
||||
"sd | mean Δval vs β=1 | mean Δtest vs β=1 | mean Δval vs current best | "
|
||||
"mean Δtest vs current best | improved |\n"
|
||||
"|---|---|---|---|---|---|---|---|---|\n")
|
||||
for r in read_csv(OUT / "confirm_summary.csv"):
|
||||
auto.append(f"| `{r['variant']}` | {f(r['mean_delta_val_vs_original'])} | "
|
||||
f"{f(r['sd_delta_val_vs_original'])} | "
|
||||
f"{r['positive_pairs_val_vs_original']}/{r['n_pairs']} | "
|
||||
f"{f(r['mean_delta_test_vs_original'])} | "
|
||||
f"{f(r['sd_delta_test_vs_original'])} | "
|
||||
f"{f(r['mean_delta_val_vs_beta1'])} | "
|
||||
f"{f(r['mean_delta_test_vs_beta1'])} | "
|
||||
f"{f(r.get('mean_delta_val_vs_current_best'))} | "
|
||||
f"{f(r.get('mean_delta_test_vs_current_best'))} | "
|
||||
f"{r['improved_vs_original_per_plan']} |\n")
|
||||
auto.append("\n")
|
||||
auto.append("### 5.4 Reference configurations on the confirmation seeds\n\n")
|
||||
auto.append("| config | mean Δval vs orig | sd | positive | mean Δtest vs orig | sd | positive |\n"
|
||||
"|---|---|---|---|---|---|---|\n")
|
||||
for r in read_csv(OUT / "confirm_reference_summary.csv"):
|
||||
auto.append(f"| `{r['config']}` | {f(r['mean_delta_val_vs_original'])} | "
|
||||
f"{f(r['sd_delta_val_vs_original'])} | {r['positive_pairs_val']} | "
|
||||
f"{f(r['mean_delta_test_vs_original'])} | "
|
||||
f"{f(r['sd_delta_test_vs_original'])} | {r['positive_pairs_test']} |\n")
|
||||
auto.append("\n")
|
||||
auto.append("### 5.5 Reference consistency (environment check)\n\n")
|
||||
auto.append("| condition | new original val | restored original val | sweep β=0 val | "
|
||||
"new − restored | new − sweep β=0 |\n|---|---|---|---|---|---|\n")
|
||||
for r in read_csv(OUT / "reference_consistency.csv"):
|
||||
auto.append(f"| {r['condition']} | {f(r['new_original_val_global'])} | "
|
||||
f"{f(r['restored_original_val_global'])} | "
|
||||
f"{f(r['sweep_beta0_val_global'])} | {f(r['new_minus_restored'])} | "
|
||||
f"{f(r['new_minus_sweep_beta0'])} |\n")
|
||||
auto.append("\n")
|
||||
auto.append("### 5.6 Wall time and memory\n\n")
|
||||
auto.append("| phase | run | status | wall h | peak GiB |\n|---|---|---|---|---|\n")
|
||||
for r in read_csv(OUT / "walltime.csv"):
|
||||
auto.append(f"| {r['phase']} | `{r['run_id']}` | {r['status']} | "
|
||||
f"{f(r['wall_h'],2)} | {f(r['peak_rss_gib'],2)} |\n")
|
||||
auto.append("\n")
|
||||
bad = [r for r in inv if r["status"] in ("failed", "incomplete", "queued")]
|
||||
auto.append("### 5.7 Failed or missing runs\n\n")
|
||||
if not bad:
|
||||
auto.append("None.\n")
|
||||
else:
|
||||
for r in bad:
|
||||
auto.append(f"- `{r['run_id']}` ({r['phase']}): {r['status']}, "
|
||||
f"exit {r['exit_code']}, {r['notes']}\n")
|
||||
|
||||
report = EXPL / "REPORT.md"
|
||||
if report.is_file():
|
||||
text = report.read_text(encoding="utf-8")
|
||||
start = "<!-- AUTO_RESULTS_START -->"
|
||||
end = "<!-- AUTO_RESULTS_END -->"
|
||||
if start in text and end in text:
|
||||
pre = text.split(start, 1)[0] + start + "\n"
|
||||
post = "\n" + end + text.split(end, 1)[1]
|
||||
report.write_text(pre + "".join(auto) + post, encoding="utf-8")
|
||||
|
||||
print(json.dumps({"screened": len(screen_rows), "confirm_rows": len(confirm_rows),
|
||||
"summary_rows": len(summary),
|
||||
"failed": [r["run_id"] for r in inv if r["status"] == "failed"]},
|
||||
indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python
|
||||
"""Per-class and per-client effects of the confirmed variants (post-freeze).
|
||||
|
||||
Reads the 20 confirmation runs and the matching original baseline runs. Writes
|
||||
two CSVs in exploration_v2/analysis/. Descriptive only; no selection.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import statistics as st
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
RUNS = REPO / "exploration_v2" / "results" / "runs"
|
||||
OUT = REPO / "exploration_v2" / "analysis"
|
||||
PAIRS = [("xiiotid", 0.25, 3), ("xiiotid", 0.25, 4),
|
||||
("5gnidd", 0.5, 3), ("5gnidd", 0.5, 4)]
|
||||
VARIANTS = ["v_shrink__b1__lam0.5", "v_cap__b1__c4",
|
||||
"support_weighted__beta0.5", "support_weighted__beta1"]
|
||||
|
||||
|
||||
def rows(p):
|
||||
with p.open(newline="", encoding="utf-8") as fh:
|
||||
return list(csv.DictReader(fh))
|
||||
|
||||
|
||||
def base(rid):
|
||||
return RUNS / rid / "results" / rid
|
||||
|
||||
|
||||
def write(name, data):
|
||||
if not data:
|
||||
return
|
||||
with (OUT / name).open("w", newline="", encoding="utf-8") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=list(data[0]))
|
||||
w.writeheader()
|
||||
w.writerows(data)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
cls_rows, cli_rows = [], []
|
||||
for ds, alpha, seed in PAIRS:
|
||||
b = f"{ds}__alpha{alpha:g}__seed{seed}__original_protean"
|
||||
bp = {int(r["class_id"]): r for r in rows(base(b) / "test_per_class.csv")}
|
||||
bm = {int(r["client_id"]): r for r in rows(base(b) / "val_per_client.csv")}
|
||||
for label in VARIANTS:
|
||||
c = f"{ds}__alpha{alpha:g}__seed{seed}__{label}"
|
||||
cp = {int(r["class_id"]): r for r in rows(base(c) / "test_per_class.csv")}
|
||||
for cid, br in bp.items():
|
||||
if float(br["support"]) <= 0:
|
||||
continue
|
||||
cr = cp.get(cid)
|
||||
if cr is None:
|
||||
continue
|
||||
cls_rows.append({
|
||||
"dataset": ds, "alpha": alpha, "seed": seed, "variant": label,
|
||||
"class_id": cid, "class_name": br["class_name"],
|
||||
"test_support": int(float(br["support"])),
|
||||
"base_f1": br["f1"], "variant_f1": cr["f1"],
|
||||
"delta_f1": float(cr["f1"]) - float(br["f1"]),
|
||||
"base_recall": br["recall"], "variant_recall": cr["recall"],
|
||||
"delta_recall": float(cr["recall"]) - float(br["recall"]),
|
||||
})
|
||||
cm = {int(r["client_id"]): r for r in rows(base(c) / "val_per_client.csv")}
|
||||
for cid, br in bm.items():
|
||||
cr = cm.get(cid)
|
||||
if cr is None or br["rare_class_macro_f1"] in ("", None):
|
||||
continue
|
||||
if cr["rare_class_macro_f1"] in ("", None):
|
||||
continue
|
||||
cli_rows.append({
|
||||
"dataset": ds, "alpha": alpha, "seed": seed, "variant": label,
|
||||
"client_id": cid, "n_samples": cr["n_samples"],
|
||||
"base_val_rare_f1": br["rare_class_macro_f1"],
|
||||
"variant_val_rare_f1": cr["rare_class_macro_f1"],
|
||||
"delta_val_rare_f1": (float(cr["rare_class_macro_f1"])
|
||||
- float(br["rare_class_macro_f1"])),
|
||||
})
|
||||
write("confirm_per_class_variant.csv", cls_rows)
|
||||
write("confirm_per_client_variant.csv", cli_rows)
|
||||
|
||||
# compact pooled summary for the two confirmed variants
|
||||
for label in VARIANTS:
|
||||
print("VAR", label)
|
||||
for ds in ("xiiotid", "5gnidd"):
|
||||
sub = [r for r in cls_rows if r["variant"] == label and r["dataset"] == ds]
|
||||
by = {}
|
||||
for r in sub:
|
||||
by.setdefault(r["class_name"], []).append(r["delta_f1"])
|
||||
order = sorted(by, key=lambda k: -st.fmean(by[k]))
|
||||
print(" ", ds, [(k, round(st.fmean(by[k]), 3)) for k in order])
|
||||
cc = [r for r in cli_rows if r["variant"] == label and r["dataset"] == ds]
|
||||
d = [r["delta_val_rare_f1"] for r in cc]
|
||||
print(" per-client mean %.4f improve/degrade %d/%d" % (
|
||||
st.fmean(d), sum(1 for x in d if x > 0), sum(1 for x in d if x < 0)))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env python
|
||||
"""Build exploration_v2/queue_confirm.csv from the frozen ranking.json.
|
||||
|
||||
Confirmation design (PLAN.md §6): top-2 variants plus three reference configs
|
||||
(original, support_weighted beta=0.5, support_weighted beta=1.0) on the two
|
||||
screening conditions and the two new seeds 3 and 4.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
EXPL = REPO / "exploration_v2"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ranking = json.loads((EXPL / "ranking.json").read_text(encoding="utf-8"))
|
||||
top2 = ranking["top2"]
|
||||
if len(top2) != 2:
|
||||
raise SystemExit(f"ranking.json does not contain 2 candidates: {top2}")
|
||||
|
||||
specs = {}
|
||||
with (EXPL / "queue_screen.csv").open(newline="", encoding="utf-8") as fh:
|
||||
for row in csv.DictReader(fh):
|
||||
specs[row["label"]] = row
|
||||
for label in top2:
|
||||
if label not in specs:
|
||||
raise SystemExit(f"top candidate {label} has no screening spec")
|
||||
|
||||
rows = []
|
||||
for ds, alpha in (("xiiotid", 0.25), ("5gnidd", 0.5)):
|
||||
for seed in (3, 4):
|
||||
base = f"{ds}__alpha{alpha:g}__seed{seed}"
|
||||
rows.append(dict(run_id=f"{base}__original_protean", dataset=ds,
|
||||
alpha=alpha, seed=seed, mode="original_protean",
|
||||
beta="", shrink="", cap="", minsup="",
|
||||
part_dir="exploration_v2/partitions",
|
||||
label="original_protean", role="reference"))
|
||||
for b in ("0.5", "1"):
|
||||
rows.append(dict(run_id=f"{base}__support_weighted__beta{b}",
|
||||
dataset=ds, alpha=alpha, seed=seed,
|
||||
mode="support_weighted", beta=b, shrink="", cap="",
|
||||
minsup="", part_dir="exploration_v2/partitions",
|
||||
label=f"support_weighted__beta{b}",
|
||||
role="reference"))
|
||||
for label in top2:
|
||||
s = specs[label]
|
||||
rows.append(dict(run_id=f"{base}__{label}", dataset=ds,
|
||||
alpha=alpha, seed=seed, mode=s["mode"],
|
||||
beta=s["beta"], shrink=s["shrink"], cap=s["cap"],
|
||||
minsup=s["minsup"],
|
||||
part_dir="exploration_v2/partitions",
|
||||
label=label, role="confirm_variant"))
|
||||
|
||||
out = EXPL / "queue_confirm.csv"
|
||||
with out.open("w", newline="", encoding="utf-8") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=list(rows[0]))
|
||||
w.writeheader()
|
||||
w.writerows(rows)
|
||||
print(f"wrote {out} ({len(rows)} rows) top2={top2}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python
|
||||
"""Create one new-seed partition manifest inside exploration_v2/.
|
||||
|
||||
This reuses the frozen project partition procedure
|
||||
(``protean_research.data.pipeline.create_partition`` ->
|
||||
``per_class_dirichlet_multinomial``) and the frozen split/preprocessing code.
|
||||
It never writes into ``artifacts/partitions``.
|
||||
|
||||
Usage:
|
||||
python exploration_v2/scripts/make_manifest_v2.py --dataset xiiotid --alpha 0.25 --seed 3
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
|
||||
from protean_research.data import manifest as manifest_mod # noqa: E402
|
||||
from protean_research.data import rare_unseen # noqa: E402
|
||||
from protean_research.data.characterization import characterize_support # noqa: E402
|
||||
from protean_research.data.pipeline import ( # noqa: E402
|
||||
create_partition,
|
||||
prepare_dataset,
|
||||
preprocessing_content_hash,
|
||||
)
|
||||
from protean_research.utils.config import load_datasets_config # noqa: E402
|
||||
|
||||
|
||||
def write_csv(path: Path, rows: list[dict]) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
if not rows:
|
||||
path.write_text("", encoding="utf-8")
|
||||
return
|
||||
with path.open("w", newline="", encoding="utf-8") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=list(rows[0].keys()))
|
||||
w.writeheader()
|
||||
w.writerows(rows)
|
||||
|
||||
|
||||
def main(argv=None) -> int:
|
||||
ap = argparse.ArgumentParser(description=__doc__)
|
||||
ap.add_argument("--dataset", required=True)
|
||||
ap.add_argument("--alpha", type=float, required=True)
|
||||
ap.add_argument("--seed", type=int, required=True)
|
||||
ap.add_argument("--clients", type=int, default=10)
|
||||
ap.add_argument("--partitions-dir", default=None)
|
||||
ap.add_argument("--analysis-dir", default=None)
|
||||
args = ap.parse_args(argv)
|
||||
|
||||
partitions_dir = Path(args.partitions_dir or REPO / "exploration_v2" / "partitions")
|
||||
analysis_dir = Path(args.analysis_dir or REPO / "exploration_v2" / "analysis" / "partitions")
|
||||
partitions_dir.mkdir(parents=True, exist_ok=True)
|
||||
analysis_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
datasets_cfg = load_datasets_config()
|
||||
bundle = prepare_dataset(args.dataset, seed=args.seed, datasets_cfg=datasets_cfg)
|
||||
pre_hash = preprocessing_content_hash(bundle.preprocessor)
|
||||
path = manifest_mod.manifest_path(partitions_dir, args.dataset, args.alpha, args.seed)
|
||||
if path.exists():
|
||||
manifest = manifest_mod.load_manifest(path)
|
||||
print(f"exists: {path}")
|
||||
else:
|
||||
manifest, assignments, support = create_partition(
|
||||
bundle,
|
||||
alpha=args.alpha,
|
||||
seed=args.seed,
|
||||
num_clients=args.clients,
|
||||
partition_dir=partitions_dir,
|
||||
preprocessing_hash=pre_hash,
|
||||
)
|
||||
print(f"created: {path}")
|
||||
|
||||
# Exact reload check against the stored recipe.
|
||||
split, assignments, support = manifest_mod.reproduce_train_assignments(
|
||||
manifest, bundle.labels)
|
||||
tag = f"{args.dataset}__alpha{args.alpha:g}__seed{args.seed}"
|
||||
write_csv(analysis_dir / f"{tag}__characterization.csv",
|
||||
characterize_support(support, bundle.class_names))
|
||||
write_csv(analysis_dir / f"{tag}__rare_unseen.csv",
|
||||
rare_unseen.rare_unseen_rows(
|
||||
support, bundle.class_names, bundle.cleaned.benign_index,
|
||||
args.dataset, args.alpha, args.seed))
|
||||
meta = {
|
||||
"dataset": args.dataset,
|
||||
"alpha": args.alpha,
|
||||
"seed": args.seed,
|
||||
"manifest_path": str(path),
|
||||
"partition_hash": manifest["partition_hash"],
|
||||
"manifest_content_hash": manifest_mod.manifest_content_hash(manifest),
|
||||
"preprocessing_hash": pre_hash,
|
||||
"num_clients": args.clients,
|
||||
"num_classes": len(bundle.class_names),
|
||||
"created_utc": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
"procedure": "protean_research.data.pipeline.create_partition "
|
||||
"(per_class_dirichlet_multinomial), frozen split/preprocessing",
|
||||
}
|
||||
(analysis_dir / f"{tag}__manifest_meta.json").write_text(
|
||||
json.dumps(meta, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||
print(json.dumps({"manifest": str(path), "partition_hash": meta["partition_hash"]}))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,421 @@
|
||||
#!/usr/bin/env python
|
||||
"""Phase 2 read-only diagnosis of the existing 108-run grid.
|
||||
|
||||
Reads only already-restored result directories (results/<run>/) plus the
|
||||
committed summary tables under artifacts/analysis/. Writes only inside
|
||||
exploration_v2/results/. Does not import project code, does not train.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import json
|
||||
import math
|
||||
import statistics as st
|
||||
from itertools import product
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
OUT = REPO / "exploration_v2" / "results"
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
DATASETS = ["xiiotid", "5gnidd"]
|
||||
ALPHAS = [0.25, 0.5, 0.75]
|
||||
SEEDS = [0, 1, 2]
|
||||
BETAS = [0.0, 0.25, 0.5, 0.75, 1.0]
|
||||
|
||||
|
||||
def read_json(path):
|
||||
with path.open(encoding="utf-8") as fh:
|
||||
return json.load(fh)
|
||||
|
||||
|
||||
def read_csv(path):
|
||||
with path.open(newline="", encoding="utf-8") as fh:
|
||||
return list(csv.DictReader(fh))
|
||||
|
||||
|
||||
def fnum(v):
|
||||
if v is None or v == "":
|
||||
return None
|
||||
try:
|
||||
return float(v)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def run_dir(dataset, alpha, seed, tag):
|
||||
return REPO / "results" / f"{dataset}__alpha{alpha:g}__seed{seed}__{tag}"
|
||||
|
||||
|
||||
def tag_for(beta):
|
||||
if beta is None:
|
||||
return "original_protean"
|
||||
return f"support_weighted__beta{beta:g}"
|
||||
|
||||
|
||||
def load_run(dataset, alpha, seed, beta):
|
||||
d = run_dir(dataset, alpha, seed, tag_for(beta))
|
||||
if not d.is_dir():
|
||||
return None
|
||||
rec = {
|
||||
"dataset": dataset, "alpha": alpha, "seed": seed,
|
||||
"beta": beta, "mode": "original" if beta is None else "support_weighted",
|
||||
"dir": str(d.relative_to(REPO)),
|
||||
}
|
||||
for name in ["metadata", "val_selection", "val_global_metrics",
|
||||
"test_global_metrics", "history"]:
|
||||
p = d / f"{name}.json"
|
||||
rec[name] = read_json(p) if p.exists() else None
|
||||
for name in ["val_per_client", "per_client", "val_per_class", "test_per_class",
|
||||
"train_support_Nij", "rare_unseen"]:
|
||||
p = d / f"{name}.csv"
|
||||
rec[name] = read_csv(p) if p.exists() else None
|
||||
return rec
|
||||
|
||||
|
||||
def support_stats(rec, class_names):
|
||||
rows = rec.get("train_support_Nij") or []
|
||||
if not rows:
|
||||
return {}
|
||||
support = []
|
||||
for r in rows:
|
||||
support.append([int(float(r[c])) for c in class_names])
|
||||
n_clients = len(support)
|
||||
n_classes = len(class_names)
|
||||
per_class = []
|
||||
for j in range(n_classes):
|
||||
vals = [support[i][j] for i in range(n_clients)]
|
||||
pos = [v for v in vals if v > 0]
|
||||
total = sum(vals)
|
||||
if not pos:
|
||||
per_class.append({"class_id": j, "n_contrib": 0, "cv": None,
|
||||
"max_share": 0.0, "min_pos": 0, "max_pos": 0})
|
||||
continue
|
||||
mean = sum(pos) / len(pos)
|
||||
sd = st.pstdev(pos) if len(pos) > 1 else 0.0
|
||||
beta1 = [v ** 1.0 for v in pos]
|
||||
per_class.append({
|
||||
"class_id": j,
|
||||
"n_contrib": len(pos),
|
||||
"cv": (sd / mean) if mean else None,
|
||||
"max_share": max(beta1) / sum(beta1) if sum(beta1) else None,
|
||||
"min_pos": min(pos),
|
||||
"max_pos": max(pos),
|
||||
"max_over_min": (max(pos) / min(pos)) if min(pos) else None,
|
||||
})
|
||||
cvs = [p["cv"] for p in per_class if p["cv"] is not None]
|
||||
return {
|
||||
"client_sizes": [sum(row) for row in support],
|
||||
"mean_support_cv": st.fmean(cvs) if cvs else None,
|
||||
"max_support_cv": max(cvs) if cvs else None,
|
||||
"n_classes_lt_M": sum(1 for p in per_class if p["n_contrib"] < n_clients),
|
||||
"n_classes_singleton": sum(1 for p in per_class if p["n_contrib"] == 1),
|
||||
"max_weight_share_beta1": max(
|
||||
(p["max_share"] for p in per_class if p["max_share"] is not None), default=None),
|
||||
"mean_weight_share_beta1": st.fmean(
|
||||
[p["max_share"] for p in per_class if p["max_share"] is not None])
|
||||
if any(p["max_share"] is not None for p in per_class) else None,
|
||||
"per_class": per_class,
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
runs = {}
|
||||
for dataset, alpha, seed in product(DATASETS, ALPHAS, SEEDS):
|
||||
ref = load_run(dataset, alpha, seed, None)
|
||||
if ref is None:
|
||||
print(f"MISSING original {dataset} {alpha} {seed}")
|
||||
continue
|
||||
class_names = ref["metadata"]["class_names"]
|
||||
runs[(dataset, alpha, seed, None)] = ref
|
||||
for beta in BETAS:
|
||||
r = load_run(dataset, alpha, seed, beta)
|
||||
if r is None:
|
||||
print(f"MISSING beta {dataset} {alpha} {seed} {beta}")
|
||||
continue
|
||||
runs[(dataset, alpha, seed, beta)] = r
|
||||
|
||||
# ---------- per-run metric table ----------
|
||||
rows = []
|
||||
for (dataset, alpha, seed, beta), rec in runs.items():
|
||||
vs = rec.get("val_selection") or {}
|
||||
vg = rec.get("val_global_metrics") or {}
|
||||
tg = rec.get("test_global_metrics") or {}
|
||||
md = rec.get("metadata") or {}
|
||||
class_names = md.get("class_names") or []
|
||||
ss = support_stats(rec, class_names)
|
||||
rows.append({
|
||||
"dataset": dataset, "alpha": alpha, "seed": seed,
|
||||
"mode": rec["mode"], "beta": "" if beta is None else beta,
|
||||
"val_sel_per_client_rare_f1": vs.get("val_rare_class_macro_f1_per_client_mean"),
|
||||
"val_rare_f1_global": vg.get("rare_class_macro_f1"),
|
||||
"val_rare_recall_global": vg.get("rare_class_recall"),
|
||||
"val_macro_f1": vg.get("macro_f1"),
|
||||
"val_accuracy": vg.get("accuracy"),
|
||||
"val_weighted_f1": vg.get("weighted_f1"),
|
||||
"test_rare_f1_global": tg.get("rare_class_macro_f1"),
|
||||
"test_rare_recall_global": tg.get("rare_class_recall"),
|
||||
"test_macro_f1": tg.get("macro_f1"),
|
||||
"test_accuracy": tg.get("accuracy"),
|
||||
"test_weighted_f1": tg.get("weighted_f1"),
|
||||
"rare_support_test": tg.get("rare_support"),
|
||||
"val_rare_support": vg.get("rare_support"),
|
||||
"mean_support_cv": ss.get("mean_support_cv"),
|
||||
"max_support_cv": ss.get("max_support_cv"),
|
||||
"n_classes_lt_M": ss.get("n_classes_lt_M"),
|
||||
"n_classes_singleton": ss.get("n_classes_singleton"),
|
||||
"max_weight_share_beta1": ss.get("max_weight_share_beta1"),
|
||||
"mean_weight_share_beta1": ss.get("mean_weight_share_beta1"),
|
||||
"client_size_ratio_mean": (
|
||||
st.fmean(ss["client_sizes"]) / (sum(ss["client_sizes"]) / len(ss["client_sizes"]))
|
||||
if ss.get("client_sizes") else None),
|
||||
})
|
||||
# client size ratio proper: mean client size / smallest? Use max/mean computed below.
|
||||
for r in rows:
|
||||
rec = runs[(r["dataset"], r["alpha"], r["seed"],
|
||||
None if r["mode"] == "original" else r["beta"])]
|
||||
ss = support_stats(rec, (rec["metadata"] or {}).get("class_names") or [])
|
||||
sizes = ss.get("client_sizes")
|
||||
r["client_size_ratio_mean"] = (max(sizes) / st.fmean(sizes)) if sizes else None
|
||||
|
||||
field_order = list(rows[0].keys())
|
||||
with (OUT / "phase2_per_run.csv").open("w", newline="", encoding="utf-8") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=field_order)
|
||||
w.writeheader()
|
||||
w.writerows(rows)
|
||||
|
||||
# ---------- paired deltas vs original and vs beta=0 ----------
|
||||
by_key = {(r["dataset"], r["alpha"], r["seed"], r["mode"], r["beta"]): r for r in rows}
|
||||
deltas = []
|
||||
for dataset, alpha, seed in product(DATASETS, ALPHAS, SEEDS):
|
||||
base = by_key.get((dataset, alpha, seed, "original", ""))
|
||||
b0 = by_key.get((dataset, alpha, seed, "support_weighted", 0.0))
|
||||
if not base:
|
||||
continue
|
||||
for beta in BETAS:
|
||||
cur = by_key.get((dataset, alpha, seed, "support_weighted", beta))
|
||||
if not cur:
|
||||
continue
|
||||
for refname, ref in (("vs_original", base), ("vs_beta0", b0)):
|
||||
if not ref:
|
||||
continue
|
||||
deltas.append({
|
||||
"dataset": dataset, "alpha": alpha, "seed": seed, "beta": beta,
|
||||
"reference": refname,
|
||||
"d_val_sel": (cur["val_sel_per_client_rare_f1"] or 0) - (ref["val_sel_per_client_rare_f1"] or 0),
|
||||
"d_val_rare_f1_global": (cur["val_rare_f1_global"] or 0) - (ref["val_rare_f1_global"] or 0),
|
||||
"d_test_rare_f1": (cur["test_rare_f1_global"] or 0) - (ref["test_rare_f1_global"] or 0),
|
||||
"d_val_rare_recall": (cur["val_rare_recall_global"] or 0) - (ref["val_rare_recall_global"] or 0),
|
||||
"d_test_rare_recall": (cur["test_rare_recall_global"] or 0) - (ref["test_rare_recall_global"] or 0),
|
||||
"d_val_macro_f1": (cur["val_macro_f1"] or 0) - (ref["val_macro_f1"] or 0),
|
||||
"d_test_macro_f1": (cur["test_macro_f1"] or 0) - (ref["test_macro_f1"] or 0),
|
||||
"d_val_accuracy": (cur["val_accuracy"] or 0) - (ref["val_accuracy"] or 0),
|
||||
"d_test_accuracy": (cur["test_accuracy"] or 0) - (ref["test_accuracy"] or 0),
|
||||
"val_test_gap_cur": (cur["test_rare_f1_global"] or 0) - (cur["val_rare_f1_global"] or 0),
|
||||
"val_test_gap_ref": (ref["test_rare_f1_global"] or 0) - (ref["val_rare_f1_global"] or 0),
|
||||
})
|
||||
with (OUT / "phase2_paired_deltas.csv").open("w", newline="", encoding="utf-8") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=list(deltas[0].keys()))
|
||||
w.writeheader()
|
||||
w.writerows(deltas)
|
||||
|
||||
# ---------- pooled per condition x beta ----------
|
||||
pooled = []
|
||||
for dataset, alpha in product(DATASETS, ALPHAS):
|
||||
for beta in [None] + BETAS:
|
||||
vals = []
|
||||
for seed in SEEDS:
|
||||
r = by_key.get((dataset, alpha, seed,
|
||||
"original" if beta is None else "support_weighted",
|
||||
"" if beta is None else beta))
|
||||
if r:
|
||||
vals.append(r)
|
||||
if not vals:
|
||||
continue
|
||||
def mean(key):
|
||||
xs = [v[key] for v in vals if v[key] is not None]
|
||||
return st.fmean(xs) if xs else None
|
||||
def sd(key):
|
||||
xs = [v[key] for v in vals if v[key] is not None]
|
||||
return st.stdev(xs) if len(xs) > 1 else None
|
||||
pooled.append({
|
||||
"dataset": dataset, "alpha": alpha,
|
||||
"beta": "" if beta is None else beta,
|
||||
"n_seeds": len(vals),
|
||||
"val_sel_mean": mean("val_sel_per_client_rare_f1"),
|
||||
"val_sel_sd": sd("val_sel_per_client_rare_f1"),
|
||||
"val_rare_f1_global_mean": mean("val_rare_f1_global"),
|
||||
"val_rare_f1_global_sd": sd("val_rare_f1_global"),
|
||||
"test_rare_f1_mean": mean("test_rare_f1_global"),
|
||||
"test_rare_f1_sd": sd("test_rare_f1_global"),
|
||||
"val_rare_recall_mean": mean("val_rare_recall_global"),
|
||||
"test_rare_recall_mean": mean("test_rare_recall_global"),
|
||||
"val_macro_f1_mean": mean("val_macro_f1"),
|
||||
"test_macro_f1_mean": mean("test_macro_f1"),
|
||||
"val_accuracy_mean": mean("val_accuracy"),
|
||||
"test_accuracy_mean": mean("test_accuracy"),
|
||||
"mean_support_cv": mean("mean_support_cv"),
|
||||
"mean_weight_share_beta1": mean("mean_weight_share_beta1"),
|
||||
"n_classes_lt_M": mean("n_classes_lt_M"),
|
||||
})
|
||||
with (OUT / "phase2_pooled_by_beta.csv").open("w", newline="", encoding="utf-8") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=list(pooled[0].keys()))
|
||||
w.writeheader()
|
||||
w.writerows(pooled)
|
||||
|
||||
# ---------- adjacent beta-step deltas (pooled over seeds) ----------
|
||||
steps = []
|
||||
for dataset, alpha in product(DATASETS, ALPHAS):
|
||||
seq = [0.0, 0.25, 0.5, 0.75, 1.0]
|
||||
for lo, hi in zip(seq, seq[1:]):
|
||||
dv, dt = [], []
|
||||
for seed in SEEDS:
|
||||
a = by_key.get((dataset, alpha, seed, "support_weighted", lo))
|
||||
b = by_key.get((dataset, alpha, seed, "support_weighted", hi))
|
||||
if a and b:
|
||||
dv.append((b["val_sel_per_client_rare_f1"] or 0) - (a["val_sel_per_client_rare_f1"] or 0))
|
||||
dt.append((b["test_rare_f1_global"] or 0) - (a["test_rare_f1_global"] or 0))
|
||||
steps.append({
|
||||
"dataset": dataset, "alpha": alpha, "step": f"{lo}->{hi}",
|
||||
"mean_d_val_sel": st.fmean(dv) if dv else None,
|
||||
"mean_d_test_rare_f1": st.fmean(dt) if dt else None,
|
||||
"per_seed_d_val_sel": "|".join(f"{x:.6f}" for x in dv),
|
||||
"per_seed_d_test_rare_f1": "|".join(f"{x:.6f}" for x in dt),
|
||||
"n": len(dv),
|
||||
})
|
||||
with (OUT / "phase2_beta_steps.csv").open("w", newline="", encoding="utf-8") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=list(steps[0].keys()))
|
||||
w.writeheader()
|
||||
w.writerows(steps)
|
||||
|
||||
# ---------- per-class test/val F1 deltas at beta=1 and selected beta ----------
|
||||
# Selected beta per condition = argmax pooled val selection metric.
|
||||
selected = {}
|
||||
for dataset, alpha in product(DATASETS, ALPHAS):
|
||||
cand = [p for p in pooled if p["dataset"] == dataset and p["alpha"] == alpha
|
||||
and p["beta"] != ""]
|
||||
if cand:
|
||||
best = max(cand, key=lambda p: p["val_sel_mean"])
|
||||
selected[(dataset, alpha)] = float(best["beta"])
|
||||
class_rows = []
|
||||
for dataset, alpha, seed in product(DATASETS, ALPHAS, SEEDS):
|
||||
base = runs.get((dataset, alpha, seed, None))
|
||||
if not base:
|
||||
continue
|
||||
base_class = {int(r["class_id"]): r for r in (base.get("test_per_class") or [])}
|
||||
base_vclass = {int(r["class_id"]): r for r in (base.get("val_per_class") or [])}
|
||||
for beta in [1.0, selected.get((dataset, alpha))]:
|
||||
cur = runs.get((dataset, alpha, seed, beta))
|
||||
if not cur:
|
||||
continue
|
||||
cur_class = {int(r["class_id"]): r for r in (cur.get("test_per_class") or [])}
|
||||
cur_vclass = {int(r["class_id"]): r for r in (cur.get("val_per_class") or [])}
|
||||
for cid in sorted(base_class):
|
||||
b = base_class[cid]
|
||||
c = cur_class.get(cid)
|
||||
if not c:
|
||||
continue
|
||||
bv = base_vclass.get(cid, {})
|
||||
cv = cur_vclass.get(cid, {})
|
||||
class_rows.append({
|
||||
"dataset": dataset, "alpha": alpha, "seed": seed, "beta": beta,
|
||||
"class_id": cid, "class_name": b.get("class_name"),
|
||||
"support": b.get("support"),
|
||||
"base_f1": fnum(b.get("f1")), "cur_f1": fnum(c.get("f1")),
|
||||
"delta_f1": (fnum(c.get("f1")) or 0) - (fnum(b.get("f1")) or 0),
|
||||
"base_recall": fnum(b.get("recall")), "cur_recall": fnum(c.get("recall")),
|
||||
"delta_recall": (fnum(c.get("recall")) or 0) - (fnum(b.get("recall")) or 0),
|
||||
"base_val_f1": fnum(bv.get("f1")), "cur_val_f1": fnum(cv.get("f1")),
|
||||
"delta_val_f1": ((fnum(cv.get("f1")) or 0) - (fnum(bv.get("f1")) or 0))
|
||||
if bv and cv else None,
|
||||
})
|
||||
with (OUT / "phase2_per_class_deltas.csv").open("w", newline="", encoding="utf-8") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=list(class_rows[0].keys()))
|
||||
w.writeheader()
|
||||
w.writerows(class_rows)
|
||||
|
||||
# pooled per-class delta
|
||||
class_pooled = []
|
||||
keys = sorted({(r["dataset"], r["alpha"], r["beta"], r["class_id"]) for r in class_rows})
|
||||
for dataset, alpha, beta, cid in keys:
|
||||
sub = [r for r in class_rows if r["dataset"] == dataset and r["alpha"] == alpha
|
||||
and r["beta"] == beta and r["class_id"] == cid]
|
||||
class_pooled.append({
|
||||
"dataset": dataset, "alpha": alpha, "beta": beta, "class_id": cid,
|
||||
"class_name": sub[0]["class_name"], "n_seeds": len(sub),
|
||||
"mean_delta_test_f1": st.fmean([r["delta_f1"] for r in sub]),
|
||||
"mean_delta_test_recall": st.fmean([r["delta_recall"] for r in sub]),
|
||||
"mean_delta_val_f1": st.fmean([r["delta_val_f1"] for r in sub
|
||||
if r["delta_val_f1"] is not None])
|
||||
if any(r["delta_val_f1"] is not None for r in sub) else None,
|
||||
"mean_test_support": st.fmean([float(r["support"]) for r in sub]),
|
||||
})
|
||||
with (OUT / "phase2_per_class_pooled.csv").open("w", newline="", encoding="utf-8") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=list(class_pooled[0].keys()))
|
||||
w.writeheader()
|
||||
w.writerows(class_pooled)
|
||||
|
||||
# ---------- per-client deltas (validation) at beta=1 ----------
|
||||
client_rows = []
|
||||
for dataset, alpha, seed in product(DATASETS, ALPHAS, SEEDS):
|
||||
base = runs.get((dataset, alpha, seed, None))
|
||||
cur = runs.get((dataset, alpha, seed, 1.0))
|
||||
if not base or not cur:
|
||||
continue
|
||||
bmap = {int(r["client_id"]): r for r in (base.get("val_per_client") or [])}
|
||||
for r in cur.get("val_per_client") or []:
|
||||
cid = int(r["client_id"])
|
||||
b = bmap.get(cid)
|
||||
if not b:
|
||||
continue
|
||||
bv = fnum(b.get("rare_class_macro_f1"))
|
||||
cv = fnum(r.get("rare_class_macro_f1"))
|
||||
client_rows.append({
|
||||
"dataset": dataset, "alpha": alpha, "seed": seed, "client_id": cid,
|
||||
"n_samples": r.get("n_samples"),
|
||||
"base_val_rare_f1": bv, "cur_val_rare_f1": cv,
|
||||
"delta_val_rare_f1": (cv - bv) if bv is not None and cv is not None else None,
|
||||
"base_val_rare_recall": fnum(b.get("rare_class_recall")),
|
||||
"cur_val_rare_recall": fnum(r.get("rare_class_recall")),
|
||||
})
|
||||
with (OUT / "phase2_per_client_delta_beta1.csv").open("w", newline="", encoding="utf-8") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=list(client_rows[0].keys()))
|
||||
w.writeheader()
|
||||
w.writerows(client_rows)
|
||||
|
||||
# ---------- displacement table ----------
|
||||
disp = {}
|
||||
disp_path = REPO / "artifacts" / "analysis" / "final__prototype_displacement_by_beta.csv"
|
||||
if disp_path.exists():
|
||||
for r in read_csv(disp_path):
|
||||
disp[(r["dataset"], float(r["alpha"]), float(r["beta"]))] = float(r["mean_displacement"])
|
||||
|
||||
# ---------- summary JSON ----------
|
||||
def cond_mean(sel, key):
|
||||
xs = [r[key] for r in rows if sel(r) and r[key] is not None]
|
||||
return st.fmean(xs) if xs else None
|
||||
|
||||
worst = sorted(
|
||||
[d for d in deltas if d["reference"] == "vs_original"],
|
||||
key=lambda d: d["d_test_rare_f1"])[:10]
|
||||
summary = {
|
||||
"n_runs_loaded": len(runs),
|
||||
"selected_beta_by_condition": {f"{k[0]}__a{k[1]}": v for k, v in selected.items()},
|
||||
"pooled_pooled": pooled,
|
||||
"largest_test_losses_vs_original": worst,
|
||||
"displacement_beta1": {f"{k[0]}__a{k[1]}": v for k, v in disp.items() if k[2] == 1.0},
|
||||
}
|
||||
(OUT / "phase2_summary.json").write_text(json.dumps(summary, indent=2), encoding="utf-8")
|
||||
|
||||
print(json.dumps({
|
||||
"runs": len(runs),
|
||||
"rows": len(rows),
|
||||
"deltas": len(deltas),
|
||||
"selected": summary["selected_beta_by_condition"],
|
||||
}, indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,446 @@
|
||||
#!/usr/bin/env python
|
||||
"""Unattended driver for exploration_v2.
|
||||
|
||||
Phases: smoke -> screening -> rank (freeze) -> confirm -> analysis -> DONE.
|
||||
|
||||
Safety properties
|
||||
-----------------
|
||||
* one driver at a time (flock held by driver.sh)
|
||||
* resumable from filesystem markers (COMPLETE / .failed / .running / scopes)
|
||||
* retries a failed run once, from a clean directory
|
||||
* concurrency <= 3 processes and <= 36 GiB of MemoryMax caps; <= 2 5G-NIDD
|
||||
* heartbeat written every loop (target: < 1 minute old)
|
||||
* STOP, failure-rate, budget and repeated-memory-kill stop rules from PLAN.md
|
||||
* never kills a process it did not start; on resume it only observes scopes
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import fcntl
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
EXPL = Path(__file__).resolve().parents[1]
|
||||
RUNS = EXPL / "results" / "runs"
|
||||
ATTEMPTS = EXPL / "results" / "attempts"
|
||||
LOGS = EXPL / "logs"
|
||||
STATE = EXPL / "state.json"
|
||||
HEARTBEAT = EXPL / "HEARTBEAT"
|
||||
STOP = EXPL / "STOP"
|
||||
DONE = EXPL / "DONE"
|
||||
STOP_REASON = EXPL / "STOP_REASON"
|
||||
ISSUES = EXPL / "ISSUES.md"
|
||||
BUDGET_START = EXPL / "BUDGET_START"
|
||||
RUN_ONE = EXPL / "run_one_v2.sh"
|
||||
PY = REPO / ".venv" / "bin" / "python"
|
||||
|
||||
MEM_CAP = {"xiiotid": 13, "5gnidd": 15} # GiB; X-IIoTID raised 11->13 after OOMs
|
||||
MEM_TOTAL = 36
|
||||
MAX_PROCS = 2
|
||||
MAX_5GNIDD = 2
|
||||
MIN_AVAILABLE_GIB = 12.0 # host-level guard before launching
|
||||
BUDGET_HOURS = 96
|
||||
|
||||
|
||||
def utc():
|
||||
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
|
||||
def now_epoch():
|
||||
return time.time()
|
||||
|
||||
|
||||
def unit_for(run_id: str) -> str:
|
||||
h = hashlib.sha1(run_id.encode()).hexdigest()[:12]
|
||||
return f"explorev2-{h}"
|
||||
|
||||
|
||||
def scope_active(unit: str) -> bool:
|
||||
try:
|
||||
r = subprocess.run(["systemctl", "--user", "is-active", "--quiet", f"{unit}.scope"],
|
||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=20)
|
||||
return r.returncode == 0
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def read_csv(path: Path):
|
||||
if not path.is_file():
|
||||
return []
|
||||
with path.open(newline="", encoding="utf-8") as fh:
|
||||
return list(csv.DictReader(fh))
|
||||
|
||||
|
||||
def load_state():
|
||||
if STATE.is_file():
|
||||
try:
|
||||
return json.loads(STATE.read_text(encoding="utf-8"))
|
||||
except Exception:
|
||||
pass
|
||||
return {"phase": "smoke", "attempts": {}, "terminal_failed": [],
|
||||
"max_procs": MAX_PROCS, "notes": [], "budget_start_utc": None,
|
||||
"screening_started": False, "ranking_frozen": False}
|
||||
|
||||
|
||||
def save_state(st):
|
||||
tmp = STATE.with_suffix(".tmp")
|
||||
tmp.write_text(json.dumps(st, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||
os.replace(tmp, STATE)
|
||||
|
||||
|
||||
def append_issue(msg: str):
|
||||
with ISSUES.open("a", encoding="utf-8") as fh:
|
||||
fh.write(f"\n## {utc()} — driver\n\n{msg}\n")
|
||||
|
||||
|
||||
def run_dir(run_id: str) -> Path:
|
||||
return RUNS / run_id
|
||||
|
||||
|
||||
def primary_ok(rid: str) -> bool:
|
||||
d = run_dir(rid)
|
||||
res = d / "results" / rid
|
||||
ana = d / "analysis" / f"{rid}__prototype_snapshot.json"
|
||||
need = [
|
||||
res / "metadata.json", res / "history.json",
|
||||
res / "test_global_metrics.json", res / "test_confusion_matrix.json",
|
||||
res / "test_per_class.csv", res / "val_global_metrics.json",
|
||||
res / "val_selection.json", res / "per_client.csv",
|
||||
res / "val_per_client.csv", res / "train_support_Nij.csv",
|
||||
res / "characterization.csv", res / "rare_unseen.csv", ana,
|
||||
]
|
||||
return all(p.is_file() and p.stat().st_size > 0 for p in need)
|
||||
|
||||
|
||||
def status_of(rid: str):
|
||||
d = run_dir(rid)
|
||||
if (d / "COMPLETE").is_file() and primary_ok(rid):
|
||||
return "done"
|
||||
if (d / ".failed").is_file():
|
||||
return "failed"
|
||||
if (d / ".running").is_file() or scope_active(unit_for(rid)):
|
||||
return "running"
|
||||
if d.is_dir():
|
||||
return "incomplete"
|
||||
return "queued"
|
||||
|
||||
|
||||
def archive_attempt(rid: str, n: int):
|
||||
src = run_dir(rid)
|
||||
if not src.exists():
|
||||
return
|
||||
ATTEMPTS.mkdir(parents=True, exist_ok=True)
|
||||
k = n
|
||||
dst = ATTEMPTS / f"{rid}__attempt{k}"
|
||||
while dst.exists():
|
||||
k += 1
|
||||
dst = ATTEMPTS / f"{rid}__attempt{k}"
|
||||
shutil.move(str(src), str(dst))
|
||||
|
||||
|
||||
def terminal(st: dict, rid: str) -> bool:
|
||||
return status_of(rid) == "done" or rid in st["terminal_failed"]
|
||||
|
||||
|
||||
def any_memory_kill_recent(st: dict, window: int = 2) -> bool:
|
||||
recent = st.get("recent_exits", [])[-window:]
|
||||
return len(recent) == window and all(x == 137 for x in recent)
|
||||
|
||||
|
||||
def write_heartbeat(st: dict, running: dict, phase: str, note: str = ""):
|
||||
HEARTBEAT.write_text(json.dumps({
|
||||
"utc": utc(),
|
||||
"epoch": round(now_epoch(), 1),
|
||||
"pid": os.getpid(),
|
||||
"phase": phase,
|
||||
"running": sorted(running),
|
||||
"running_count": len(running),
|
||||
"max_procs": st.get("max_procs", MAX_PROCS),
|
||||
"note": note,
|
||||
}, indent=2) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def launch(row: dict) -> subprocess.Popen:
|
||||
cmd = [
|
||||
"bash", str(RUN_ONE),
|
||||
row["run_id"], row["dataset"], str(row["alpha"]), str(row["seed"]),
|
||||
row["mode"], str(row["beta"] or "0"),
|
||||
str(row["shrink"] or "0"), str(row["cap"] or "0"),
|
||||
str(row["minsup"] or "0"), row["part_dir"], row["label"],
|
||||
]
|
||||
LOGS.mkdir(parents=True, exist_ok=True)
|
||||
logf = LOGS / f"{row['run_id']}.driver.log"
|
||||
with logf.open("a") as fh:
|
||||
fh.write(f"[{utc()}] launch: {' '.join(cmd)}\n")
|
||||
fh.flush()
|
||||
return subprocess.Popen(cmd, stdout=fh, stderr=subprocess.STDOUT,
|
||||
cwd=str(REPO), start_new_session=True)
|
||||
|
||||
|
||||
def mem_available_gib() -> float:
|
||||
try:
|
||||
with open("/proc/meminfo", encoding="ascii") as fh:
|
||||
for line in fh:
|
||||
if line.startswith("MemAvailable:"):
|
||||
return int(line.split()[1]) / (1024 * 1024)
|
||||
except Exception:
|
||||
return 0.0
|
||||
return 0.0
|
||||
|
||||
|
||||
def can_launch(st: dict, running: dict, row: dict) -> bool:
|
||||
if mem_available_gib() < MIN_AVAILABLE_GIB:
|
||||
return False
|
||||
if len(running) >= int(st.get("max_procs", MAX_PROCS)):
|
||||
return False
|
||||
ds = row["dataset"]
|
||||
used = sum(MEM_CAP.get(r["dataset"], 11) for r in running.values())
|
||||
if used + MEM_CAP.get(ds, 11) > MEM_TOTAL:
|
||||
return False
|
||||
if ds == "5gnidd":
|
||||
if sum(1 for r in running.values() if r["dataset"] == "5gnidd") >= MAX_5GNIDD:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def prepare_retry(st: dict, rid: str) -> bool:
|
||||
"""Archive a failed/incomplete attempt. Return True if a retry is allowed."""
|
||||
n = int(st["attempts"].get(rid, 0))
|
||||
if n >= 1:
|
||||
if rid not in st["terminal_failed"]:
|
||||
st["terminal_failed"].append(rid)
|
||||
append_issue(f"run `{rid}` failed after {n + 1} attempt(s); marked terminal failed.")
|
||||
return False
|
||||
st["attempts"][rid] = n + 1
|
||||
archive_attempt(rid, n + 1)
|
||||
save_state(st)
|
||||
return True
|
||||
|
||||
|
||||
def run_script(name: str, *args) -> int:
|
||||
cmd = [str(PY), str(EXPL / "scripts" / name), *args]
|
||||
logf = LOGS / f"{name}.log"
|
||||
with logf.open("a") as fh:
|
||||
fh.write(f"\n[{utc()}] {' '.join(cmd)}\n")
|
||||
fh.flush()
|
||||
r = subprocess.run(cmd, stdout=fh, stderr=subprocess.STDOUT, cwd=str(REPO))
|
||||
return r.returncode
|
||||
|
||||
|
||||
def main() -> int:
|
||||
EXPL.mkdir(parents=True, exist_ok=True)
|
||||
st = load_state()
|
||||
if STOP.is_file():
|
||||
write_heartbeat(st, {}, "stopped", "STOP exists at startup")
|
||||
append_issue("STOP exists at driver startup; no run launched.")
|
||||
return 0
|
||||
|
||||
# smoke (re-run after the plan hash; non-scientific)
|
||||
if not (EXPL / "smoke" / "SMOKE.json").is_file() or st.get("phase") == "smoke":
|
||||
rc = run_script("smoke_test.py")
|
||||
if rc != 0:
|
||||
append_issue(f"smoke test failed (rc={rc}); see exploration_v2/smoke/SMOKE.json. Aborting.")
|
||||
STOP_REASON.write_text(f"smoke failure at {utc()}\n", encoding="utf-8")
|
||||
return 1
|
||||
st["phase"] = "screening"
|
||||
save_state(st)
|
||||
|
||||
running: dict[str, dict] = {}
|
||||
procs: dict[str, subprocess.Popen] = {}
|
||||
last_hb = 0.0
|
||||
stall_loops = 0
|
||||
|
||||
while True:
|
||||
if time.time() - last_hb >= 15:
|
||||
write_heartbeat(st, running, st["phase"])
|
||||
last_hb = time.time()
|
||||
|
||||
# observe finished children
|
||||
for rid in list(procs):
|
||||
p = procs[rid]
|
||||
rc = p.poll()
|
||||
if rc is not None:
|
||||
del procs[rid]
|
||||
running.pop(rid, None)
|
||||
st.setdefault("recent_exits", []).append(rc)
|
||||
st["recent_exits"] = st["recent_exits"][-4:]
|
||||
save_state(st)
|
||||
if rc != 0:
|
||||
append_issue(f"run `{rid}` wrapper exit {rc}; see its logs.")
|
||||
if rc == 137:
|
||||
if any_memory_kill_recent(st):
|
||||
old = int(st.get("max_procs", MAX_PROCS))
|
||||
st["max_procs"] = max(1, old - 1)
|
||||
append_issue(f"two consecutive exit-137 kills; lowering max_procs "
|
||||
f"from {old} to {st['max_procs']} and continuing.")
|
||||
save_state(st)
|
||||
|
||||
# observe resumable scopes (driver may have been restarted)
|
||||
if st["phase"] in ("screening", "confirm"):
|
||||
queue = (read_csv(EXPL / "queue_screen.csv") if st["phase"] == "screening"
|
||||
else read_csv(EXPL / "queue_confirm.csv"))
|
||||
for row in queue:
|
||||
rid = row["run_id"]
|
||||
if rid in procs:
|
||||
continue
|
||||
if scope_active(unit_for(rid)) and rid not in running:
|
||||
running[rid] = row
|
||||
# drop external runs whose scope has ended
|
||||
for rid in list(running):
|
||||
if rid in procs:
|
||||
continue
|
||||
if not scope_active(unit_for(rid)):
|
||||
running.pop(rid, None)
|
||||
|
||||
# stop rules
|
||||
stop_now = False
|
||||
reason = ""
|
||||
if STOP.is_file():
|
||||
stop_now, reason = True, "STOP file exists"
|
||||
elif st["phase"] in ("screening", "confirm"):
|
||||
queue = (read_csv(EXPL / "queue_screen.csv") if st["phase"] == "screening"
|
||||
else read_csv(EXPL / "queue_confirm.csv"))
|
||||
finished = [r["run_id"] for r in queue if terminal(st, r["run_id"])]
|
||||
failed = [r for r in finished if r in st["terminal_failed"]]
|
||||
if len(finished) >= 5 and len(failed) / len(finished) > 0.20:
|
||||
if any_memory_kill_recent(st):
|
||||
append_issue("failure rate would stop the driver, but the last two "
|
||||
"exits were memory kills; applying the memory throttle "
|
||||
"instead of a full stop.")
|
||||
else:
|
||||
stop_now, reason = True, (f"failure rate {len(failed)}/{len(finished)} "
|
||||
f"exceeds 20%")
|
||||
if st.get("budget_start_utc"):
|
||||
started = datetime.strptime(st["budget_start_utc"], "%Y-%m-%dT%H:%M:%SZ")
|
||||
elapsed = (datetime.now(timezone.utc) - started.replace(tzinfo=timezone.utc)).total_seconds()
|
||||
if elapsed > BUDGET_HOURS * 3600:
|
||||
stop_now, reason = True, f"96 h budget exhausted ({elapsed/3600:.1f} h)"
|
||||
if stop_now:
|
||||
append_issue(f"stopping launches: {reason}")
|
||||
STOP_REASON.write_text(f"{reason} at {utc()}\n", encoding="utf-8")
|
||||
st["phase"] = "stopped"
|
||||
save_state(st)
|
||||
|
||||
# phase transitions only when nothing is running
|
||||
if not running and not procs:
|
||||
if st["phase"] == "screening":
|
||||
queue = read_csv(EXPL / "queue_screen.csv")
|
||||
if all(terminal(st, r["run_id"]) for r in queue):
|
||||
ready = [r for r in queue if status_of(r["run_id"]) == "done"]
|
||||
labels = sorted({r["label"] for r in ready
|
||||
if r["mode"] != "original_protean"})
|
||||
if len(labels) < 3:
|
||||
append_issue(f"only {len(labels)} screening variants completed; "
|
||||
f"PLAN requires at least 3. Ranking not run.")
|
||||
st["phase"] = "stopped"
|
||||
STOP_REASON.write_text(f"fewer than 3 variants at {utc()}\n",
|
||||
encoding="utf-8")
|
||||
save_state(st)
|
||||
continue
|
||||
rc = run_script("rank_screening.py")
|
||||
if rc != 0:
|
||||
append_issue(f"rank_screening.py failed rc={rc}; aborting.")
|
||||
st["phase"] = "stopped"
|
||||
save_state(st)
|
||||
continue
|
||||
ranking = EXPL / "ranking.json"
|
||||
h = hashlib.sha256(ranking.read_bytes()).hexdigest()
|
||||
(EXPL / "ranking.sha256").write_text(
|
||||
f"{h} ranking.json\n{utc()}\n", encoding="utf-8")
|
||||
st["ranking_frozen"] = True
|
||||
rc = run_script("make_confirm_queue.py")
|
||||
if rc != 0:
|
||||
append_issue(f"make_confirm_queue.py failed rc={rc}; aborting.")
|
||||
st["phase"] = "stopped"
|
||||
save_state(st)
|
||||
continue
|
||||
# new manifests for seeds 3,4
|
||||
for ds, alpha in (("xiiotid", 0.25), ("5gnidd", 0.5)):
|
||||
for seed in (3, 4):
|
||||
rc = run_script("make_manifest_v2.py", "--dataset", ds,
|
||||
"--alpha", str(alpha), "--seed", str(seed))
|
||||
if rc != 0:
|
||||
append_issue(f"manifest generation failed for {ds} "
|
||||
f"alpha={alpha} seed={seed} rc={rc}")
|
||||
st["phase"] = "stopped"
|
||||
save_state(st)
|
||||
break
|
||||
st["phase"] = "confirm"
|
||||
save_state(st)
|
||||
continue
|
||||
elif st["phase"] == "confirm":
|
||||
queue = read_csv(EXPL / "queue_confirm.csv")
|
||||
if all(terminal(st, r["run_id"]) for r in queue):
|
||||
rc = run_script("analyze_results.py")
|
||||
if rc != 0:
|
||||
append_issue(f"analyze_results.py failed rc={rc}")
|
||||
DONE.write_text(json.dumps({
|
||||
"status": "complete" if rc == 0 else "analysis_failed",
|
||||
"utc": utc(), "runs_done": sum(1 for r in queue if status_of(r["run_id"]) == "done"),
|
||||
"runs_failed": len([r for r in queue if r["run_id"] in st["terminal_failed"]]),
|
||||
}, indent=2) + "\n", encoding="utf-8")
|
||||
st["phase"] = "done"
|
||||
save_state(st)
|
||||
write_heartbeat(st, running, "done")
|
||||
return 0 if rc == 0 else 1
|
||||
elif st["phase"] in ("stopped", "done"):
|
||||
if st["phase"] == "stopped":
|
||||
rc = run_script("analyze_results.py")
|
||||
DONE.write_text(json.dumps({
|
||||
"status": "stopped", "utc": utc(), "analysis_rc": rc,
|
||||
"reason": (STOP_REASON.read_text(encoding="utf-8").strip()
|
||||
if STOP_REASON.is_file() else "unknown"),
|
||||
}, indent=2) + "\n", encoding="utf-8")
|
||||
st["phase"] = "done"
|
||||
save_state(st)
|
||||
write_heartbeat(st, running, "done")
|
||||
return 0
|
||||
return 0
|
||||
|
||||
# launch queued runs
|
||||
if st["phase"] in ("screening", "confirm") and not STOP.is_file():
|
||||
queue = (read_csv(EXPL / "queue_screen.csv") if st["phase"] == "screening"
|
||||
else read_csv(EXPL / "queue_confirm.csv"))
|
||||
launched_any = False
|
||||
for row in queue:
|
||||
rid = row["run_id"]
|
||||
if terminal(st, rid) or rid in running or rid in procs:
|
||||
continue
|
||||
s = status_of(rid)
|
||||
if s == "failed" or s == "incomplete":
|
||||
if not prepare_retry(st, rid):
|
||||
continue
|
||||
if not can_launch(st, running, row):
|
||||
continue
|
||||
if not st.get("budget_start_utc"):
|
||||
st["budget_start_utc"] = utc()
|
||||
BUDGET_START.write_text(st["budget_start_utc"] + "\n", encoding="utf-8")
|
||||
save_state(st)
|
||||
procs[rid] = launch(row)
|
||||
running[rid] = row
|
||||
launched_any = True
|
||||
if len(running) >= int(st.get("max_procs", MAX_PROCS)):
|
||||
break
|
||||
if launched_any:
|
||||
stall_loops = 0
|
||||
elif not running:
|
||||
stall_loops += 1
|
||||
if stall_loops >= 6:
|
||||
append_issue("driver found no launchable and no running runs for 60 s; "
|
||||
"recording stall and exiting for resume.sh.")
|
||||
write_heartbeat(st, running, st["phase"], "stalled")
|
||||
return 2
|
||||
time.sleep(10)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,233 @@
|
||||
#!/usr/bin/env python
|
||||
"""Validation-only screening ranking for exploration_v2.
|
||||
|
||||
Reads ONLY ``val_*`` files. Every opened file is appended to
|
||||
``exploration_v2/ACCESS_LOG.txt`` with a UTC timestamp.
|
||||
|
||||
Writes ``exploration_v2/ranking.json``. This file is frozen (sha256 + time in
|
||||
``ranking.sha256``) before any confirmatory run starts.
|
||||
|
||||
Ranking metric (pre-registered in PLAN.md §5):
|
||||
score(V) = mean over the two screening conditions of
|
||||
[val_global_rare_f1(V) - val_global_rare_f1(original)]
|
||||
where val_global_rare_f1 = rare_class_macro_f1 in val_global_metrics.json.
|
||||
Secondary (sensitivity): the same difference using
|
||||
val_rare_class_macro_f1_per_client_mean from val_selection.json.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
EXPL = REPO / "exploration_v2"
|
||||
RUNS = EXPL / "results" / "runs"
|
||||
ACCESS = EXPL / "ACCESS_LOG.txt"
|
||||
SCREEN = EXPL / "queue_screen.csv"
|
||||
OUT = EXPL / "ranking.json"
|
||||
|
||||
CONDITIONS = {
|
||||
"S1": ("xiiotid", 0.25),
|
||||
"S2": ("5gnidd", 0.5),
|
||||
}
|
||||
BETAS = ["0", "0.25", "0.5", "0.75", "1"]
|
||||
|
||||
|
||||
def utc():
|
||||
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
|
||||
def log_access(path: Path):
|
||||
with ACCESS.open("a", encoding="utf-8") as fh:
|
||||
fh.write(f"{utc()}\t{path}\n")
|
||||
|
||||
|
||||
def read_json_val(path: Path):
|
||||
if not path.is_file():
|
||||
return None
|
||||
log_access(path)
|
||||
with path.open(encoding="utf-8") as fh:
|
||||
return json.load(fh)
|
||||
|
||||
|
||||
def val_files(base: Path):
|
||||
"""Return the two validation file paths for a run base directory."""
|
||||
return (base / "val_global_metrics.json", base / "val_selection.json")
|
||||
|
||||
|
||||
def metrics_for(val_global_path: Path, val_selection_path: Path):
|
||||
vg = read_json_val(val_global_path)
|
||||
vs = read_json_val(val_selection_path)
|
||||
if vg is None and vs is None:
|
||||
return None
|
||||
return {
|
||||
"val_global_rare_f1": (vg or {}).get("rare_class_macro_f1"),
|
||||
"val_global_rare_recall": (vg or {}).get("rare_class_recall"),
|
||||
"val_global_macro_f1": (vg or {}).get("macro_f1"),
|
||||
"val_per_client_rare_f1": (vs or {}).get("val_rare_class_macro_f1_per_client_mean"),
|
||||
"val_sel_file_present": vs is not None,
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ACCESS.parent.mkdir(parents=True, exist_ok=True)
|
||||
with ACCESS.open("a", encoding="utf-8") as fh:
|
||||
fh.write(f"# ranking.py run at {utc()}\n")
|
||||
|
||||
# ---- original references ---------------------------------------------
|
||||
# Primary: an original_protean run in the current environment/partition
|
||||
# (added as amendment A2). Fallback: the restored grid.
|
||||
original = {}
|
||||
beta_refs = {}
|
||||
baseline_source = {}
|
||||
for cid, (ds, alpha) in CONDITIONS.items():
|
||||
base_id = f"{ds}__alpha{alpha:g}__seed0__original_protean"
|
||||
new_paths = val_files(RUNS / base_id / "results" / base_id)
|
||||
old_paths = val_files(REPO / "results" / base_id)
|
||||
if new_paths[0].is_file():
|
||||
vg, vs = new_paths
|
||||
source = "in_environment_seed0"
|
||||
else:
|
||||
vg, vs = old_paths
|
||||
source = "restored_grid_seed0"
|
||||
m = metrics_for(vg, vs)
|
||||
if m is None or m["val_global_rare_f1"] is None:
|
||||
raise SystemExit(f"missing original validation metrics for {cid} ({base_id})")
|
||||
original[cid] = {"run_id": base_id, "source": source, **m}
|
||||
baseline_source[cid] = source
|
||||
beta_refs[cid] = {}
|
||||
for b in BETAS:
|
||||
rid = f"{ds}__alpha{alpha:g}__seed0__support_weighted__beta{b}"
|
||||
# Prefer the current-environment 1-thread sweep (same host and
|
||||
# library versions as the new runs) when it exists.
|
||||
sweep_paths = val_files(REPO / "results" / "sweep" / "runs" / rid / "results" / rid)
|
||||
grid_paths = val_files(REPO / "results" / rid)
|
||||
if sweep_paths[0].is_file():
|
||||
vg, vs = sweep_paths
|
||||
src = "sweep_seed0_1thread"
|
||||
else:
|
||||
vg, vs = grid_paths
|
||||
src = "restored_grid_seed0"
|
||||
mm = metrics_for(vg, vs)
|
||||
if mm is not None:
|
||||
beta_refs[cid][b] = {"run_id": rid, "source": src, **mm}
|
||||
|
||||
# ---- screening candidates -------------------------------------------
|
||||
log_access(SCREEN)
|
||||
with SCREEN.open(newline="", encoding="utf-8") as fh:
|
||||
queue = list(csv.DictReader(fh))
|
||||
|
||||
candidates = {}
|
||||
for row in queue:
|
||||
if row["mode"] == "original_protean":
|
||||
continue
|
||||
rid = row["run_id"]
|
||||
vg, vs = val_files(RUNS / rid / "results" / rid)
|
||||
m = metrics_for(vg, vs)
|
||||
if m is None or m["val_global_rare_f1"] is None:
|
||||
raise SystemExit(f"missing validation metrics for screening run {rid}")
|
||||
candidates.setdefault(row["label"], {
|
||||
"label": row["label"], "mode": row["mode"],
|
||||
"params": {"beta": float(row["beta"]),
|
||||
"shrink_lambda": float(row["shrink"]) if row["shrink"] else None,
|
||||
"cap_factor": float(row["cap"]) if row["cap"] else None,
|
||||
"min_support": float(row["minsup"]) if row["minsup"] else None},
|
||||
"conditions": {},
|
||||
})
|
||||
candidates[row["label"]]["conditions"][
|
||||
"S1" if row["dataset"] == "xiiotid" else "S2"] = {"run_id": rid, **m}
|
||||
|
||||
ranked = []
|
||||
for label, item in candidates.items():
|
||||
per = {}
|
||||
deltas_global, deltas_client = [], []
|
||||
for cid in CONDITIONS:
|
||||
cond = item["conditions"].get(cid)
|
||||
if cond is None:
|
||||
raise SystemExit(f"{label}: missing condition {cid}")
|
||||
base = original[cid]
|
||||
dg = cond["val_global_rare_f1"] - base["val_global_rare_f1"]
|
||||
dc = cond["val_per_client_rare_f1"] - base["val_per_client_rare_f1"]
|
||||
per[cid] = {
|
||||
"run_id": cond["run_id"],
|
||||
"val_global_rare_f1": cond["val_global_rare_f1"],
|
||||
"baseline_val_global_rare_f1": base["val_global_rare_f1"],
|
||||
"delta_vs_original": dg,
|
||||
"val_per_client_rare_f1": cond["val_per_client_rare_f1"],
|
||||
"baseline_val_per_client_rare_f1": base["val_per_client_rare_f1"],
|
||||
"delta_per_client_vs_original": dc,
|
||||
}
|
||||
deltas_global.append(dg)
|
||||
deltas_client.append(dc)
|
||||
item["per_condition"] = per
|
||||
item["score"] = sum(deltas_global) / len(deltas_global)
|
||||
item["min_condition_delta"] = min(deltas_global)
|
||||
item["secondary_score_per_client"] = sum(deltas_client) / len(deltas_client)
|
||||
ranked.append(item)
|
||||
|
||||
ranked.sort(key=lambda x: (-x["score"], -x["min_condition_delta"], x["label"]))
|
||||
secondary = sorted(ranked, key=lambda x: (-x["secondary_score_per_client"],
|
||||
x["label"]))
|
||||
for i, item in enumerate(ranked, 1):
|
||||
item["rank"] = i
|
||||
for i, item in enumerate(secondary, 1):
|
||||
item["rank_secondary"] = i
|
||||
|
||||
# ---- current-method reference per condition ------------------------
|
||||
current_ref = {}
|
||||
for cid in CONDITIONS:
|
||||
by_global = max(beta_refs[cid].items(),
|
||||
key=lambda kv: kv[1]["val_global_rare_f1"])
|
||||
by_client = max(beta_refs[cid].items(),
|
||||
key=lambda kv: kv[1]["val_per_client_rare_f1"])
|
||||
current_ref[cid] = {
|
||||
"original": original[cid],
|
||||
"best_beta_by_val_global": {
|
||||
"beta": float(by_global[0]),
|
||||
"val_global_rare_f1": by_global[1]["val_global_rare_f1"],
|
||||
"delta_vs_original": (by_global[1]["val_global_rare_f1"]
|
||||
- original[cid]["val_global_rare_f1"]),
|
||||
},
|
||||
"best_beta_by_val_per_client": {
|
||||
"beta": float(by_client[0]),
|
||||
"val_per_client_rare_f1": by_client[1]["val_per_client_rare_f1"],
|
||||
"delta_vs_original": (by_client[1]["val_per_client_rare_f1"]
|
||||
- original[cid]["val_per_client_rare_f1"]),
|
||||
},
|
||||
"all_betas": beta_refs[cid],
|
||||
}
|
||||
|
||||
top2 = [ranked[0]["label"], ranked[1]["label"]]
|
||||
payload = {
|
||||
"generated_utc": utc(),
|
||||
"stage": "screening",
|
||||
"ranking_metric": "mean over S1,S2 of val_global_rare_f1(candidate) - "
|
||||
"val_global_rare_f1(original)",
|
||||
"secondary_metric": "same with val_rare_class_macro_f1_per_client_mean",
|
||||
"conditions": {k: {"dataset": v[0], "alpha": v[1]} for k, v in CONDITIONS.items()},
|
||||
"screening_seed": 0,
|
||||
"baseline_source": baseline_source,
|
||||
"original": original,
|
||||
"current_method_reference": current_ref,
|
||||
"candidates": ranked,
|
||||
"secondary_ranking_order": [x["label"] for x in secondary],
|
||||
"top2": top2,
|
||||
"selection_margin_top1_minus_top2": ranked[0]["score"] - ranked[1]["score"],
|
||||
"note": "Validation only. No test metric of any new run was read before "
|
||||
"this file was frozen.",
|
||||
}
|
||||
OUT.write_text(json.dumps(payload, indent=2, sort_keys=False) + "\n",
|
||||
encoding="utf-8")
|
||||
print(json.dumps({"top2": top2,
|
||||
"ranking": [(x["label"], round(x["score"], 6)) for x in ranked],
|
||||
"margin": payload["selection_margin_top1_minus_top2"]},
|
||||
indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Executable
+303
@@ -0,0 +1,303 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Record one sweep run in summary.csv and write/validate COMPLETE markers.
|
||||
|
||||
Two subcommands:
|
||||
|
||||
record -- upsert one row in results/sweep/summary.csv (flock-protected)
|
||||
marker -- validate the primary artifacts of a finished run and write COMPLETE
|
||||
|
||||
The summary is keyed by run config, so re-running a failed config replaces its
|
||||
row instead of appending a duplicate. A completed row is never downgraded to
|
||||
"skipped_complete" or "stopped".
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import fcntl
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
HEADER = [
|
||||
"config",
|
||||
"dataset",
|
||||
"alpha",
|
||||
"beta",
|
||||
"seed",
|
||||
"aggregation_mode",
|
||||
"status",
|
||||
"wall_s",
|
||||
"cpu_user_s",
|
||||
"cpu_sys_s",
|
||||
"percent_cpu",
|
||||
"peak_rss_kb",
|
||||
"exit_code",
|
||||
"started_utc",
|
||||
"ended_utc",
|
||||
"run_dir",
|
||||
"log_dir",
|
||||
"notes",
|
||||
]
|
||||
|
||||
|
||||
def utcnow() -> str:
|
||||
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
|
||||
def _elapsed_to_seconds(value: str) -> float | None:
|
||||
value = value.strip()
|
||||
parts = value.split(":")
|
||||
try:
|
||||
if len(parts) == 3:
|
||||
return int(parts[0]) * 3600 + int(parts[1]) * 60 + float(parts[2])
|
||||
if len(parts) == 2:
|
||||
return int(parts[0]) * 60 + float(parts[1])
|
||||
if len(parts) == 1:
|
||||
return float(parts[0])
|
||||
except ValueError:
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
def parse_time_file(path: str | None) -> dict:
|
||||
out = {
|
||||
"wall_s": "",
|
||||
"cpu_user_s": "",
|
||||
"cpu_sys_s": "",
|
||||
"percent_cpu": "",
|
||||
"peak_rss_kb": "",
|
||||
}
|
||||
if not path:
|
||||
return out
|
||||
p = Path(path)
|
||||
if not p.is_file() or p.stat().st_size == 0:
|
||||
return out
|
||||
text = p.read_text(encoding="utf-8", errors="replace")
|
||||
|
||||
patterns = {
|
||||
"cpu_user_s": r"User time \(seconds\):\s*([0-9.]+)",
|
||||
"cpu_sys_s": r"System time \(seconds\):\s*([0-9.]+)",
|
||||
"percent_cpu": r"Percent of CPU this job got:\s*([0-9.]+)%",
|
||||
"peak_rss_kb": r"Maximum resident set size \(kbytes\):\s*([0-9]+)",
|
||||
}
|
||||
for key, pat in patterns.items():
|
||||
m = re.search(pat, text)
|
||||
if m:
|
||||
out[key] = m.group(1)
|
||||
|
||||
m = re.search(r"Elapsed \(wall clock\) time \(h:mm:ss or m:ss\):\s*(\S+)", text)
|
||||
if m:
|
||||
wall = _elapsed_to_seconds(m.group(1))
|
||||
if wall is not None:
|
||||
out["wall_s"] = f"{wall:.2f}"
|
||||
return out
|
||||
|
||||
|
||||
def _read_rows(path: Path) -> list[dict]:
|
||||
if not path.is_file() or path.stat().st_size == 0:
|
||||
return []
|
||||
with path.open(newline="", encoding="utf-8") as handle:
|
||||
rows = list(csv.DictReader(handle))
|
||||
for row in rows:
|
||||
for key in HEADER:
|
||||
row.setdefault(key, "")
|
||||
return rows
|
||||
|
||||
|
||||
def _write_rows(path: Path, rows: list[dict]) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
fd, tmp = tempfile.mkstemp(
|
||||
dir=str(path.parent), prefix=".summary.", suffix=".csv", text=True
|
||||
)
|
||||
try:
|
||||
with os.fdopen(fd, "w", newline="", encoding="utf-8") as handle:
|
||||
writer = csv.DictWriter(handle, fieldnames=HEADER)
|
||||
writer.writeheader()
|
||||
for row in rows:
|
||||
writer.writerow({key: row.get(key, "") for key in HEADER})
|
||||
os.replace(tmp, path)
|
||||
finally:
|
||||
if os.path.exists(tmp):
|
||||
os.unlink(tmp)
|
||||
|
||||
|
||||
def upsert(summary: Path, lock: Path, row: dict) -> None:
|
||||
summary.parent.mkdir(parents=True, exist_ok=True)
|
||||
with lock.open("a+", encoding="utf-8") as handle:
|
||||
fcntl.flock(handle.fileno(), fcntl.LOCK_EX)
|
||||
rows = _read_rows(summary)
|
||||
index = next(
|
||||
(i for i, item in enumerate(rows) if item.get("config") == row["config"]),
|
||||
None,
|
||||
)
|
||||
if index is None:
|
||||
rows.append({key: row.get(key, "") for key in HEADER})
|
||||
else:
|
||||
old = rows[index]
|
||||
if old.get("status") == "completed" and row.get("status") in (
|
||||
"skipped_complete",
|
||||
"stopped",
|
||||
):
|
||||
pass # never downgrade a completed run
|
||||
elif row.get("status") == "completed":
|
||||
# A fresh completion replaces the whole row, clearing stale
|
||||
# failure notes from an earlier attempt.
|
||||
rows[index] = {key: row.get(key, "") for key in HEADER}
|
||||
else:
|
||||
for key in HEADER:
|
||||
value = row.get(key, "")
|
||||
if value not in ("", None) or key in ("status", "exit_code"):
|
||||
old[key] = value
|
||||
rows[index] = old
|
||||
_write_rows(summary, rows)
|
||||
fcntl.flock(handle.fileno(), fcntl.LOCK_UN)
|
||||
|
||||
|
||||
def sha256_file(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as handle:
|
||||
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def required_files(run_dir: Path, run_name: str) -> list[Path]:
|
||||
results = run_dir / "results" / run_name
|
||||
analysis = run_dir / "analysis"
|
||||
return [
|
||||
results / "metadata.json",
|
||||
results / "history.json",
|
||||
results / "test_global_metrics.json",
|
||||
results / "test_confusion_matrix.json",
|
||||
results / "test_per_class.csv",
|
||||
results / "val_global_metrics.json",
|
||||
results / "val_selection.json",
|
||||
results / "val_per_class.csv",
|
||||
results / "per_client.csv",
|
||||
results / "val_per_client.csv",
|
||||
results / "train_support_Nij.csv",
|
||||
results / "characterization.csv",
|
||||
results / "rare_unseen.csv",
|
||||
analysis / f"{run_name}__prototype_snapshot.json",
|
||||
]
|
||||
|
||||
|
||||
def cmd_record(args: argparse.Namespace) -> int:
|
||||
timing = parse_time_file(args.time_file)
|
||||
row = {
|
||||
"config": args.run_name,
|
||||
"dataset": args.dataset,
|
||||
"alpha": args.alpha,
|
||||
"beta": args.beta,
|
||||
"seed": str(args.seed),
|
||||
"aggregation_mode": args.aggregation_mode,
|
||||
"status": args.status,
|
||||
"wall_s": timing["wall_s"],
|
||||
"cpu_user_s": timing["cpu_user_s"],
|
||||
"cpu_sys_s": timing["cpu_sys_s"],
|
||||
"percent_cpu": timing["percent_cpu"],
|
||||
"peak_rss_kb": timing["peak_rss_kb"],
|
||||
"exit_code": str(args.exit_code),
|
||||
"started_utc": args.started or "",
|
||||
"ended_utc": args.ended or utcnow(),
|
||||
"run_dir": str(Path(args.run_dir)),
|
||||
"log_dir": str(Path(args.log_dir)),
|
||||
"notes": args.notes or "",
|
||||
}
|
||||
upsert(Path(args.summary), Path(args.lock), row)
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_marker(args: argparse.Namespace) -> int:
|
||||
run_dir = Path(args.run_dir)
|
||||
missing = [
|
||||
str(path)
|
||||
for path in required_files(run_dir, args.run_name)
|
||||
if not path.is_file() or path.stat().st_size == 0
|
||||
]
|
||||
if missing:
|
||||
print("refusing to write COMPLETE; missing/empty artifacts:", file=sys.stderr)
|
||||
for path in missing:
|
||||
print(f" {path}", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
timing = parse_time_file(args.time_file)
|
||||
primary = {}
|
||||
for path in required_files(run_dir, args.run_name):
|
||||
primary[str(path.relative_to(run_dir))] = sha256_file(path)
|
||||
|
||||
payload = {
|
||||
"run_name": args.run_name,
|
||||
"dataset": args.dataset,
|
||||
"alpha": args.alpha,
|
||||
"beta": args.beta,
|
||||
"seed": args.seed,
|
||||
"aggregation_mode": args.aggregation_mode,
|
||||
"exit_code": args.exit_code,
|
||||
"finished_utc": args.finished or utcnow(),
|
||||
"wall_s": timing["wall_s"],
|
||||
"cpu_user_s": timing["cpu_user_s"],
|
||||
"cpu_sys_s": timing["cpu_sys_s"],
|
||||
"percent_cpu": timing["percent_cpu"],
|
||||
"peak_rss_kb": timing["peak_rss_kb"],
|
||||
"required_files_sha256": primary,
|
||||
}
|
||||
marker = run_dir / "COMPLETE"
|
||||
marker.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||
print(f"wrote {marker}")
|
||||
return 0
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
sub = parser.add_subparsers(dest="command", required=True)
|
||||
|
||||
rec = sub.add_parser("record")
|
||||
rec.add_argument("--summary", required=True)
|
||||
rec.add_argument("--lock", required=True)
|
||||
rec.add_argument("--run-name", required=True)
|
||||
rec.add_argument("--dataset", required=True)
|
||||
rec.add_argument("--alpha", required=True)
|
||||
rec.add_argument("--beta", required=True)
|
||||
rec.add_argument("--seed", type=int, default=0)
|
||||
rec.add_argument("--aggregation-mode", default="unknown")
|
||||
rec.add_argument("--status", required=True)
|
||||
rec.add_argument("--exit-code", type=int, required=True)
|
||||
rec.add_argument("--time-file", default=None)
|
||||
rec.add_argument("--started", default=None)
|
||||
rec.add_argument("--ended", default=None)
|
||||
rec.add_argument("--run-dir", required=True)
|
||||
rec.add_argument("--log-dir", required=True)
|
||||
rec.add_argument("--notes", default=None)
|
||||
rec.set_defaults(func=cmd_record)
|
||||
|
||||
mk = sub.add_parser("marker")
|
||||
mk.add_argument("--run-dir", required=True)
|
||||
mk.add_argument("--run-name", required=True)
|
||||
mk.add_argument("--dataset", required=True)
|
||||
mk.add_argument("--alpha", required=True)
|
||||
mk.add_argument("--beta", required=True)
|
||||
mk.add_argument("--seed", type=int, default=0)
|
||||
mk.add_argument("--aggregation-mode", default="unknown")
|
||||
mk.add_argument("--exit-code", type=int, required=True)
|
||||
mk.add_argument("--time-file", default=None)
|
||||
mk.add_argument("--finished", default=None)
|
||||
mk.set_defaults(func=cmd_marker)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def main(argv=None) -> int:
|
||||
args = build_parser().parse_args(argv)
|
||||
return args.func(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,493 @@
|
||||
#!/usr/bin/env python
|
||||
"""exploration_v2 copy of scripts/run_baseline.py with aggregation variants.
|
||||
|
||||
This file is a *copy*; the original ``scripts/run_baseline.py`` is untouched.
|
||||
Only three things differ:
|
||||
|
||||
1. the repository root is resolved two levels up (this copy lives in
|
||||
``exploration_v2/scripts/``);
|
||||
2. ``--aggregation-mode`` also accepts the exploration variants defined in
|
||||
``exploration_v2/scripts/variants.py``, and their hyperparameters are
|
||||
explicit CLI flags;
|
||||
3. the server prototype aggregator is monkey-patched to the variant dispatcher
|
||||
for the duration of this process. The baseline and ``support_weighted``
|
||||
modes are delegated to the unmodified project implementation.
|
||||
|
||||
Every default output directory points inside ``exploration_v2/`` so that a
|
||||
missing flag can never write into the tracked ``results/`` or
|
||||
``artifacts/analysis/`` trees.
|
||||
|
||||
Usage (smoke)::
|
||||
|
||||
python exploration_v2/scripts/run_variant.py --dataset xiiotid --alpha 0.5 \
|
||||
--seed 0 --max-rows 4000 --clients 4 --rounds 2 --local-epochs 1
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
sys.path.insert(0, str(REPO_ROOT / "src"))
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from protean_research.data import manifest as manifest_mod # noqa: E402
|
||||
from protean_research.data import partition as partition_mod # noqa: E402
|
||||
from protean_research.data import rare_unseen # noqa: E402
|
||||
from protean_research.aggregation import validate_beta # noqa: E402
|
||||
from protean_research.data.characterization import characterize_support # noqa: E402
|
||||
from protean_research.data.pipeline import ( # noqa: E402
|
||||
create_partition,
|
||||
prepare_dataset,
|
||||
preprocessing_content_hash,
|
||||
)
|
||||
from protean_research.evaluation.metrics import ( # noqa: E402
|
||||
classification_metrics,
|
||||
rare_class_metrics,
|
||||
)
|
||||
from protean_research.federated import TrainingConfig, run_federated # noqa: E402
|
||||
from protean_research.models.protean_cnn import extract_embeddings # noqa: E402
|
||||
from protean_research.models.prototypes import nearest_prototype_predict # noqa: E402
|
||||
from protean_research.utils.config import ( # noqa: E402
|
||||
expand_path,
|
||||
load_datasets_config,
|
||||
load_yaml,
|
||||
)
|
||||
|
||||
import variants as variants_mod # noqa: E402
|
||||
|
||||
MODE_CHOICES = list(variants_mod.ALL_MODES)
|
||||
|
||||
|
||||
def parse_args(argv=None) -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--dataset", required=True)
|
||||
parser.add_argument("--alpha", type=float, required=True)
|
||||
parser.add_argument("--seed", type=int, default=0)
|
||||
parser.add_argument("--clients", type=int, default=10)
|
||||
parser.add_argument("--rounds", type=int, default=10)
|
||||
parser.add_argument("--local-epochs", type=int, default=3)
|
||||
parser.add_argument("--batch-size", type=int, default=256)
|
||||
parser.add_argument("--lr", type=float, default=1e-3)
|
||||
parser.add_argument("--mu", type=float, default=0.1)
|
||||
parser.add_argument("--lam", type=float, default=1.0)
|
||||
parser.add_argument(
|
||||
"--aggregation-mode",
|
||||
choices=MODE_CHOICES,
|
||||
default="original_protean",
|
||||
help="server-side prototype aggregation mode (default: frozen baseline).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--beta",
|
||||
type=float,
|
||||
default=None,
|
||||
help="support-weighting exponent; required for every weighted mode.",
|
||||
)
|
||||
parser.add_argument("--shrink-lambda", type=float, default=0.5,
|
||||
help="v_shrink: weight on the support-weighted vector (rest goes to equal).")
|
||||
parser.add_argument("--cap-factor", type=float, default=4.0,
|
||||
help="v_cap: cap each raw weight at cap_factor * median raw weight.")
|
||||
parser.add_argument("--min-support", type=float, default=10.0,
|
||||
help="v_minsup: drop contributors with N_ij below this threshold.")
|
||||
parser.add_argument("--variant-label", default=None,
|
||||
help="short label used in the run directory name.")
|
||||
parser.add_argument(
|
||||
"--max-rows",
|
||||
type=int,
|
||||
default=None,
|
||||
help="SMOKE ONLY: limit how many raw rows are read; never use for science.",
|
||||
)
|
||||
parser.add_argument("--sample-from", type=int, default=200000,
|
||||
help="SMOKE ONLY: rows to read before random subsampling.")
|
||||
parser.add_argument("--partitions-dir", default=None)
|
||||
parser.add_argument("--processed-dir", default=None)
|
||||
parser.add_argument("--results-dir", default=None)
|
||||
parser.add_argument("--analysis-dir", default=None)
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
def write_json(path: Path, payload) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with path.open("w", encoding="utf-8") as handle:
|
||||
json.dump(payload, handle, indent=2, sort_keys=True)
|
||||
handle.write("\n")
|
||||
|
||||
|
||||
def write_csv(path: Path, rows: list[dict]) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
if not rows:
|
||||
path.write_text("", encoding="utf-8")
|
||||
return
|
||||
fieldnames = list(rows[0].keys())
|
||||
with path.open("w", encoding="utf-8", newline="") as handle:
|
||||
writer = csv.DictWriter(handle, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
writer.writerows(rows)
|
||||
|
||||
|
||||
def main(argv=None) -> int:
|
||||
args = parse_args(argv)
|
||||
|
||||
if args.aggregation_mode == "original_protean":
|
||||
if args.beta is not None:
|
||||
raise SystemExit(
|
||||
"--beta is only valid with a weighted aggregation mode"
|
||||
)
|
||||
beta = None
|
||||
else:
|
||||
if args.beta is None:
|
||||
raise SystemExit(
|
||||
"--beta is required with a weighted aggregation mode"
|
||||
)
|
||||
raw_beta = float(args.beta)
|
||||
if not (raw_beta == raw_beta) or raw_beta in (float("inf"), float("-inf")):
|
||||
raise SystemExit(f"--beta must be finite, got {args.beta!r}")
|
||||
if args.aggregation_mode == "v_beta":
|
||||
if raw_beta < 0.0 or raw_beta > 2.0:
|
||||
raise SystemExit("v_beta requires 0 <= beta <= 2")
|
||||
beta = raw_beta
|
||||
else:
|
||||
beta = validate_beta(raw_beta)
|
||||
|
||||
if args.shrink_lambda < 0.0 or args.shrink_lambda > 1.0:
|
||||
raise SystemExit("--shrink-lambda must lie in [0, 1]")
|
||||
if args.cap_factor < 1.0:
|
||||
raise SystemExit("--cap-factor must be >= 1")
|
||||
|
||||
# Patch the server aggregator for this process only. The project modules on
|
||||
# disk are not modified. Baseline and support_weighted delegate inside
|
||||
# variants.aggregate_variant to the unmodified project implementation.
|
||||
from protean_research.federated import server as server_mod
|
||||
|
||||
def _variant_aggregator(client_prototypes, client_supports, num_classes,
|
||||
mode=None, beta=None):
|
||||
return variants_mod.aggregate_from_client_dicts(
|
||||
client_prototypes,
|
||||
client_supports,
|
||||
num_classes,
|
||||
mode=mode,
|
||||
beta=beta,
|
||||
shrink_lambda=args.shrink_lambda,
|
||||
cap_factor=args.cap_factor,
|
||||
min_support=args.min_support,
|
||||
)
|
||||
|
||||
server_mod.aggregate_prototypes = _variant_aggregator
|
||||
|
||||
datasets_cfg = load_datasets_config()
|
||||
protocol = load_yaml(REPO_ROOT / "configs" / "experiments" / "experiment_protocol.yaml")
|
||||
|
||||
artifacts_cfg = protocol.get("artifacts", {})
|
||||
# Safe defaults: never write into the tracked trees. Callers pass explicit
|
||||
# directories for scientific runs.
|
||||
partitions_dir = expand_path(
|
||||
args.partitions_dir or REPO_ROOT / "exploration_v2" / "partitions")
|
||||
processed_dir = expand_path(
|
||||
args.processed_dir or REPO_ROOT / "exploration_v2" / "processed")
|
||||
analysis_dir = expand_path(
|
||||
args.analysis_dir or REPO_ROOT / "exploration_v2" / "analysis")
|
||||
results_root = expand_path(
|
||||
args.results_dir or REPO_ROOT / "exploration_v2" / "results")
|
||||
|
||||
# Smoke runs must never pollute the tracked partition/analysis directories.
|
||||
if args.max_rows is not None:
|
||||
if args.partitions_dir is None:
|
||||
partitions_dir = processed_dir / "smoke" / "partitions"
|
||||
if args.analysis_dir is None:
|
||||
analysis_dir = processed_dir / "smoke" / "analysis"
|
||||
if args.results_dir is None:
|
||||
results_root = results_root / "smoke"
|
||||
|
||||
if args.max_rows is not None:
|
||||
from protean_research.data import loading as loading_mod
|
||||
import numpy as np
|
||||
|
||||
spec = loading_mod.load_spec(args.dataset, datasets_cfg)
|
||||
pool = loading_mod.read_raw(spec, nrows=args.sample_from)
|
||||
rng = np.random.default_rng(args.seed)
|
||||
take = min(args.max_rows, len(pool))
|
||||
chosen = np.sort(rng.choice(len(pool), size=take, replace=False))
|
||||
pool = pool.iloc[chosen].reset_index(drop=True)
|
||||
bundle = prepare_dataset(
|
||||
args.dataset, seed=args.seed, datasets_cfg=datasets_cfg, raw_frame=pool
|
||||
)
|
||||
else:
|
||||
bundle = prepare_dataset(args.dataset, seed=args.seed, datasets_cfg=datasets_cfg)
|
||||
|
||||
# ---- partition (create or reload) -------------------------------------
|
||||
pre_hash = preprocessing_content_hash(bundle.preprocessor)
|
||||
manifest_file = manifest_mod.manifest_path(partitions_dir, args.dataset, args.alpha, args.seed)
|
||||
if manifest_file.exists():
|
||||
manifest = manifest_mod.load_manifest(manifest_file)
|
||||
split, assignments, support = manifest_mod.reproduce_train_assignments(manifest, bundle.labels)
|
||||
# Reuse the manifest's split for pairing; verify it matches the bundle.
|
||||
bundle.split = split
|
||||
else:
|
||||
manifest, assignments, support = create_partition(
|
||||
bundle, alpha=args.alpha, seed=args.seed, num_clients=args.clients,
|
||||
partition_dir=partitions_dir, preprocessing_hash=pre_hash,
|
||||
)
|
||||
manifest_reload_ok = True
|
||||
try:
|
||||
manifest_mod.reproduce_train_assignments(manifest, bundle.labels)
|
||||
except Exception: # pragma: no cover - surfaced in metadata
|
||||
manifest_reload_ok = False
|
||||
|
||||
labels = bundle.labels
|
||||
train_features = bundle.features[bundle.split.train]
|
||||
train_labels = labels[bundle.split.train]
|
||||
val_features = bundle.features[bundle.split.validation]
|
||||
val_labels = labels[bundle.split.validation]
|
||||
test_features = bundle.features[bundle.split.test]
|
||||
test_labels = labels[bundle.split.test]
|
||||
|
||||
benign_index = bundle.cleaned.benign_index
|
||||
per_client_rare = rare_unseen.rare_class_ids(support, benign_index)
|
||||
union_rare = sorted({c for row in per_client_rare for c in row})
|
||||
|
||||
cfg = TrainingConfig(
|
||||
rounds=args.rounds,
|
||||
local_epochs=args.local_epochs,
|
||||
batch_size=args.batch_size,
|
||||
learning_rate=args.lr,
|
||||
mu=args.mu,
|
||||
lam=args.lam,
|
||||
num_clients=args.clients,
|
||||
aggregation_mode=args.aggregation_mode,
|
||||
beta=beta,
|
||||
)
|
||||
result = run_federated(
|
||||
train_features=train_features,
|
||||
train_labels=train_labels,
|
||||
assignments=assignments,
|
||||
val_features=val_features,
|
||||
val_labels=val_labels,
|
||||
num_classes=bundle.num_classes,
|
||||
input_dim=bundle.features.shape[1],
|
||||
config=cfg,
|
||||
init_seed_parts=(args.dataset, f"seed={args.seed}"),
|
||||
rare_class_ids=union_rare,
|
||||
)
|
||||
|
||||
model = result["model"]
|
||||
global_prototypes = result["global_prototypes"]
|
||||
|
||||
# ---- global test evaluation ------------------------------------------
|
||||
test_embeddings = extract_embeddings(model, test_features)
|
||||
test_pred = nearest_prototype_predict(test_embeddings, global_prototypes)
|
||||
test_metrics = classification_metrics(test_labels, test_pred, bundle.num_classes)
|
||||
test_rare = rare_class_metrics(test_labels, test_pred, bundle.num_classes, union_rare)
|
||||
|
||||
# ---- per-client evaluation -------------------------------------------
|
||||
eval_assignments, eval_rng = partition_mod.partition_eval_split(
|
||||
test_labels, args.clients, args.alpha, args.dataset, args.seed, "test"
|
||||
)
|
||||
per_client_rows = []
|
||||
for client_id in range(args.clients):
|
||||
idx = eval_assignments[client_id]
|
||||
if len(idx) == 0:
|
||||
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, test_features[idx])
|
||||
pred = nearest_prototype_predict(emb, global_prototypes)
|
||||
metrics = classification_metrics(test_labels[idx], pred, bundle.num_classes)
|
||||
rare_ids = per_client_rare[client_id]
|
||||
if rare_ids:
|
||||
rare = rare_class_metrics(test_labels[idx], pred, bundle.num_classes, rare_ids)
|
||||
else:
|
||||
rare = {"rare_class_macro_f1": None, "rare_class_recall": None}
|
||||
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"],
|
||||
})
|
||||
|
||||
# ---- 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.variant_label:
|
||||
mode_tag = args.variant_label
|
||||
elif args.aggregation_mode == "support_weighted":
|
||||
mode_tag = f"support_weighted__beta{beta:g}"
|
||||
elif args.aggregation_mode != "original_protean":
|
||||
if args.variant_label:
|
||||
mode_tag = args.variant_label
|
||||
elif args.aggregation_mode == "v_beta":
|
||||
mode_tag = f"v_beta__b{beta:g}"
|
||||
elif args.aggregation_mode == "v_shrink":
|
||||
mode_tag = f"v_shrink__b{beta:g}__lam{args.shrink_lambda:g}"
|
||||
elif args.aggregation_mode == "v_cap":
|
||||
mode_tag = f"v_cap__b{beta:g}__c{args.cap_factor:g}"
|
||||
elif args.aggregation_mode == "v_minsup":
|
||||
mode_tag = f"v_minsup__t{args.min_support:g}"
|
||||
elif args.aggregation_mode == "v_logweight":
|
||||
mode_tag = "v_logweight"
|
||||
else: # pragma: no cover
|
||||
mode_tag = args.aggregation_mode
|
||||
run_name = f"{args.dataset}__alpha{args.alpha:g}__seed{args.seed}__{mode_tag}"
|
||||
run_dir = results_root / run_name
|
||||
run_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
metadata = {
|
||||
"run_name": run_name,
|
||||
"dataset": args.dataset,
|
||||
"alpha": args.alpha,
|
||||
"seed": args.seed,
|
||||
"num_clients": args.clients,
|
||||
"num_classes": bundle.num_classes,
|
||||
"class_names": bundle.class_names,
|
||||
"benign_class": bundle.spec.benign_label,
|
||||
"aggregation_mode": args.aggregation_mode,
|
||||
"beta": beta,
|
||||
"variant": {
|
||||
"label": mode_tag,
|
||||
"shrink_lambda": args.shrink_lambda
|
||||
if args.aggregation_mode == "v_shrink" else None,
|
||||
"cap_factor": args.cap_factor
|
||||
if args.aggregation_mode == "v_cap" else None,
|
||||
"min_support": args.min_support
|
||||
if args.aggregation_mode == "v_minsup" else None,
|
||||
},
|
||||
"training": {
|
||||
"rounds": args.rounds,
|
||||
"local_epochs": args.local_epochs,
|
||||
"batch_size": args.batch_size,
|
||||
"learning_rate": args.lr,
|
||||
"mu": args.mu,
|
||||
"lambda": args.lam,
|
||||
},
|
||||
"smoke": args.max_rows is not None,
|
||||
"max_rows": args.max_rows,
|
||||
"manifest_path": str(manifest_file),
|
||||
"manifest_content_hash": manifest_mod.manifest_content_hash(manifest),
|
||||
"preprocessing_hash": pre_hash,
|
||||
"manifest_reload_ok": manifest_reload_ok,
|
||||
"repo_root": str(REPO_ROOT),
|
||||
}
|
||||
write_json(run_dir / "metadata.json", metadata)
|
||||
write_json(run_dir / "history.json", result["history"])
|
||||
write_json(run_dir / "test_global_metrics.json", {
|
||||
"accuracy": test_metrics["accuracy"],
|
||||
"macro_f1": test_metrics["macro_f1"],
|
||||
"weighted_f1": test_metrics["weighted_f1"],
|
||||
**test_rare,
|
||||
})
|
||||
write_json(run_dir / "test_confusion_matrix.json", test_metrics["confusion_matrix"])
|
||||
write_csv(run_dir / "test_per_class.csv", [
|
||||
{**row, "class_name": bundle.class_names[row["class_id"]]}
|
||||
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)
|
||||
])
|
||||
write_csv(run_dir / "characterization.csv", characterize_support(support, bundle.class_names))
|
||||
write_csv(run_dir / "rare_unseen.csv", rare_unseen.rare_unseen_rows(
|
||||
support, bundle.class_names, benign_index, args.dataset, args.alpha, args.seed
|
||||
))
|
||||
|
||||
processed_dir.mkdir(parents=True, exist_ok=True)
|
||||
bundle.preprocessor.save(processed_dir / f"{args.dataset}__seed{args.seed}__preprocessor.json")
|
||||
|
||||
snapshot = result["snapshot"]
|
||||
if snapshot is not None:
|
||||
write_json(analysis_dir / f"{run_name}__prototype_snapshot.json", snapshot)
|
||||
|
||||
summary = {
|
||||
"run": run_name,
|
||||
"test_accuracy": test_metrics["accuracy"],
|
||||
"test_macro_f1": test_metrics["macro_f1"],
|
||||
"test_rare_class_macro_f1": test_rare["rare_class_macro_f1"],
|
||||
"n_global_prototypes": len(global_prototypes),
|
||||
"history_last": result["history"][-1] if result["history"] else None,
|
||||
"results_dir": str(run_dir),
|
||||
}
|
||||
print(json.dumps(summary, indent=2, sort_keys=True))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python
|
||||
"""Very short smoke slice of every aggregation variant.
|
||||
|
||||
Checks, in order:
|
||||
1. the exploration unit tests pass (``exploration_v2/tests``);
|
||||
2. the baseline run completes and writes validation artifacts;
|
||||
3. ``support_weighted`` beta=0 and ``v_beta`` beta=0 reproduce the baseline
|
||||
validation metric within a documented smoke tolerance;
|
||||
4. every candidate variant completes.
|
||||
|
||||
This is a runtime sanity check, not a scientific comparison. It writes only
|
||||
inside ``exploration_v2/smoke``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
HERE = REPO / "exploration_v2"
|
||||
SMOKE = HERE / "smoke"
|
||||
PY = REPO / ".venv" / "bin" / "python"
|
||||
RUNNER = HERE / "scripts" / "run_variant.py"
|
||||
|
||||
TOL = 1e-3
|
||||
|
||||
VARIANTS = [
|
||||
# id, mode, beta, extra args, label
|
||||
("base", "original_protean", None, [], "smoke_base"),
|
||||
("beta0", "support_weighted", 0.0, [], "smoke_beta0"),
|
||||
("beta1", "support_weighted", 1.0, [], "smoke_beta1"),
|
||||
("v_beta1.5", "v_beta", 1.5, [], "smoke_v_beta1.5"),
|
||||
("v_shrink", "v_shrink", 1.0, ["--shrink-lambda", "0.5"], "smoke_v_shrink"),
|
||||
("v_cap4", "v_cap", 1.0, ["--cap-factor", "4"], "smoke_v_cap4"),
|
||||
("v_cap2", "v_cap", 1.0, ["--cap-factor", "2"], "smoke_v_cap2"),
|
||||
("v_minsup", "v_minsup", 0.0, ["--min-support", "10"], "smoke_v_minsup"),
|
||||
("v_logweight", "v_logweight", 0.0, [], "smoke_v_logweight"),
|
||||
]
|
||||
|
||||
|
||||
def utc():
|
||||
return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
|
||||
def run_one(name, mode, beta, extra, label):
|
||||
cmd = [
|
||||
str(PY), str(RUNNER),
|
||||
"--dataset", "xiiotid", "--alpha", "0.25", "--seed", "0",
|
||||
"--max-rows", "3000", "--sample-from", "30000",
|
||||
"--clients", "4", "--rounds", "2", "--local-epochs", "1",
|
||||
"--aggregation-mode", mode, "--variant-label", label,
|
||||
"--partitions-dir", str(SMOKE / "partitions"),
|
||||
"--processed-dir", str(SMOKE / "processed"),
|
||||
"--analysis-dir", str(SMOKE / "analysis"),
|
||||
"--results-dir", str(SMOKE / "results"),
|
||||
]
|
||||
if beta is not None:
|
||||
cmd[cmd.index("--aggregation-mode"):cmd.index("--aggregation-mode")] = ["--beta", str(beta)]
|
||||
cmd += extra
|
||||
env = dict(os.environ)
|
||||
for k in ("OMP_NUM_THREADS", "MKL_NUM_THREADS", "OPENBLAS_NUM_THREADS",
|
||||
"NUMEXPR_NUM_THREADS", "VECLIB_MAXIMUM_THREADS"):
|
||||
env[k] = "1"
|
||||
env["PYTHONDONTWRITEBYTECODE"] = "1"
|
||||
log = SMOKE / "logs"
|
||||
log.mkdir(parents=True, exist_ok=True)
|
||||
out = log / f"{name}.stdout.log"
|
||||
err = log / f"{name}.stderr.log"
|
||||
with out.open("w") as fo, err.open("w") as fe:
|
||||
proc = subprocess.run(cmd, stdout=fo, stderr=fe, env=env, timeout=1800)
|
||||
return proc.returncode, cmd
|
||||
|
||||
|
||||
def val_metric(result_dir: Path):
|
||||
p = result_dir / "val_global_metrics.json"
|
||||
if not p.exists():
|
||||
return None
|
||||
return float(json.loads(p.read_text())["rare_class_macro_f1"])
|
||||
|
||||
|
||||
def main() -> int:
|
||||
SMOKE.mkdir(parents=True, exist_ok=True)
|
||||
report = {"started_utc": utc(), "tolerance": TOL, "runs": {}}
|
||||
|
||||
# 1. unit tests
|
||||
unittest = subprocess.run(
|
||||
[str(PY), "-m", "pytest", str(HERE / "tests"), "-q", "-p", "no:cacheprovider"],
|
||||
cwd=str(REPO), capture_output=True, text=True,
|
||||
env={**os.environ, "PYTHONDONTWRITEBYTECODE": "1"}, timeout=600)
|
||||
report["pytest_returncode"] = unittest.returncode
|
||||
report["pytest_tail"] = (unittest.stdout + unittest.stderr).strip().splitlines()[-3:]
|
||||
if unittest.returncode != 0:
|
||||
report["verdict"] = "FAIL_UNIT_TESTS"
|
||||
(SMOKE / "SMOKE.json").write_text(json.dumps(report, indent=2))
|
||||
return 1
|
||||
|
||||
metrics = {}
|
||||
for name, mode, beta, extra, label in VARIANTS:
|
||||
rc, cmd = run_one(name, mode, beta, extra, label)
|
||||
rdir = SMOKE / "results" / f"xiiotid__alpha0.25__seed0__{label}"
|
||||
metric = val_metric(rdir)
|
||||
metrics[name] = metric
|
||||
report["runs"][name] = {
|
||||
"mode": mode, "beta": beta, "extra": extra,
|
||||
"returncode": rc, "val_rare_macro_f1": metric,
|
||||
"results_dir": str(rdir.relative_to(REPO)),
|
||||
}
|
||||
if rc != 0 or metric is None:
|
||||
report["verdict"] = f"FAIL_RUN_{name}"
|
||||
report["finished_utc"] = utc()
|
||||
(SMOKE / "SMOKE.json").write_text(json.dumps(report, indent=2))
|
||||
return 1
|
||||
|
||||
base = metrics["base"]
|
||||
checks = {}
|
||||
for name in ("beta0", "v_beta1.5"):
|
||||
# v_beta1.5 is not expected to equal baseline; only beta0 equivalence is checked.
|
||||
if name == "beta0":
|
||||
checks[name] = abs(metrics[name] - base)
|
||||
# v_beta at beta=0 is exercised by the unit tests; here we use beta1.5.
|
||||
checks["beta0_within_tolerance"] = checks["beta0"] <= TOL
|
||||
report["equivalence_checks"] = checks
|
||||
if not checks["beta0_within_tolerance"]:
|
||||
report["verdict"] = "FAIL_BETA0_EQUIVALENCE"
|
||||
else:
|
||||
report["verdict"] = "PASS"
|
||||
report["finished_utc"] = utc()
|
||||
(SMOKE / "SMOKE.json").write_text(json.dumps(report, indent=2))
|
||||
print(json.dumps({"verdict": report["verdict"],
|
||||
"beta0_abs_diff": checks["beta0"]}, indent=2))
|
||||
return 0 if report["verdict"] == "PASS" else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python
|
||||
"""Fast status table for exploration_v2 (returns immediately)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
EXPL = Path(__file__).resolve().parents[1]
|
||||
RUNS = EXPL / "results" / "runs"
|
||||
|
||||
|
||||
def read_csv(p):
|
||||
if not p.is_file():
|
||||
return []
|
||||
with p.open(newline="", encoding="utf-8") as fh:
|
||||
return list(csv.DictReader(fh))
|
||||
|
||||
|
||||
def status(rid):
|
||||
d = RUNS / rid
|
||||
if (d / "COMPLETE").is_file():
|
||||
return "done"
|
||||
if (d / ".failed").is_file():
|
||||
return "failed"
|
||||
if (d / ".running").is_file():
|
||||
return "running"
|
||||
if d.is_dir():
|
||||
return "incomplete"
|
||||
return "queued"
|
||||
|
||||
|
||||
def main():
|
||||
st = {}
|
||||
if (EXPL / "state.json").is_file():
|
||||
st = json.loads((EXPL / "state.json").read_text())
|
||||
hb = ""
|
||||
if (EXPL / "HEARTBEAT").is_file():
|
||||
try:
|
||||
hb = json.loads((EXPL / "HEARTBEAT").read_text())
|
||||
except Exception:
|
||||
hb = {}
|
||||
queue = read_csv(EXPL / "queue_screen.csv")
|
||||
phase = st.get("phase", "?")
|
||||
if phase in ("confirm", "done", "stopped"):
|
||||
queue = read_csv(EXPL / "queue_confirm.csv") or queue
|
||||
rows = []
|
||||
for r in queue:
|
||||
rows.append((r["run_id"], r["dataset"], r.get("label", ""), status(r["run_id"])))
|
||||
counts = {}
|
||||
for _, _, _, s in rows:
|
||||
counts[s] = counts.get(s, 0) + 1
|
||||
print(f"phase={phase} budget_start={st.get('budget_start_utc')} "
|
||||
f"max_procs={st.get('max_procs')}")
|
||||
print(f"heartbeat={(hb or {}).get('utc', 'MISSING')} "
|
||||
f"running={(hb or {}).get('running_count', 0)} "
|
||||
f"note={(hb or {}).get('note', '')}")
|
||||
print(f"terminal_failed={len(st.get('terminal_failed', []))} "
|
||||
f"DONE={str((EXPL / 'DONE').is_file()).lower()} "
|
||||
f"STOP={str((EXPL / 'STOP').is_file()).lower()}")
|
||||
print("counts: " + " ".join(f"{k}={v}" for k, v in sorted(counts.items())))
|
||||
print()
|
||||
print(f"{'run_id':<62} {'dataset':<8} {'label':<28} status")
|
||||
for rid, ds, label, s in rows:
|
||||
print(f"{rid:<62} {ds:<8} {label:<28} {s}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Force a single compute thread, then execute scripts/run_baseline.py.
|
||||
|
||||
The sweep design is one process = one thread. Environment variables
|
||||
(OMP_NUM_THREADS etc.) are set by the caller, but PyTorch's intra-op and
|
||||
inter-op pools are also pinned explicitly here so that no hidden pool can
|
||||
create additional worker threads.
|
||||
|
||||
Usage:
|
||||
python thread1_launcher.py /path/to/scripts/run_baseline.py [args...]
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import runpy
|
||||
import sys
|
||||
|
||||
import torch
|
||||
|
||||
torch.set_num_threads(1)
|
||||
try:
|
||||
torch.set_num_interop_threads(1)
|
||||
except RuntimeError:
|
||||
# Already initialised (should not happen before any parallel work).
|
||||
pass
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
raise SystemExit("usage: thread1_launcher.py SCRIPT [args...]")
|
||||
|
||||
script = sys.argv[1]
|
||||
sys.argv = [script] + sys.argv[2:]
|
||||
runpy.run_path(script, run_name="__main__")
|
||||
@@ -0,0 +1,161 @@
|
||||
"""Candidate server-side prototype aggregation variants (exploration_v2 only).
|
||||
|
||||
Every variant operates on the same contributor set semantics as the frozen
|
||||
project code:
|
||||
|
||||
S_j = { i | N_ij > 0 and a valid local prototype C_ij exists }
|
||||
|
||||
except ``v_minsup`` which deliberately changes the participant rule and is
|
||||
labelled as such. Missing classes are never fabricated.
|
||||
|
||||
The baseline (``original_protean``) and the current proposed method
|
||||
(``support_weighted``) are *delegated* to the unmodified project implementation
|
||||
so that their behaviour cannot drift. Only genuinely new modes are implemented
|
||||
here.
|
||||
|
||||
Mode catalogue
|
||||
--------------
|
||||
original_protean equal mean over S_j (delegated, unchanged)
|
||||
support_weighted w_i proportional to N_ij**beta in [0, 1] (delegated)
|
||||
v_beta w_i proportional to N_ij**beta, beta allowed in [0, 2]
|
||||
(extended-grid candidate; beta > 1 is outside the frozen grid)
|
||||
v_shrink p_i = N_ij**beta / sum(N_ij**beta);
|
||||
w_i = (1 - lam) / |S_j| + lam * p_i
|
||||
(shrinkage of the weight vector toward equal weighting)
|
||||
v_cap w_i proportional to min(N_ij**beta, c * median(N_ij**beta))
|
||||
(clipping/capping of the weight vector)
|
||||
v_minsup drop contributors with N_ij < t, then equal mean over the
|
||||
remaining contributors (participant-rule change)
|
||||
v_logweight w_i proportional to log1p(N_ij), normalised
|
||||
(a different, concave weight function)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from typing import Mapping, Sequence
|
||||
|
||||
import numpy as np
|
||||
|
||||
from protean_research.aggregation import aggregate_class_prototypes
|
||||
|
||||
BASELINE_MODES = ("original_protean", "support_weighted")
|
||||
VARIANT_MODES = ("v_beta", "v_shrink", "v_cap", "v_minsup", "v_logweight")
|
||||
ALL_MODES = BASELINE_MODES + VARIANT_MODES
|
||||
|
||||
|
||||
def _collect(contributions):
|
||||
"""Return class_id -> (list[vector ndarray], list[support float])."""
|
||||
out = {}
|
||||
for class_id in sorted(contributions, key=lambda c: int(c)):
|
||||
protos, supports = [], []
|
||||
for proto, support in contributions[class_id]:
|
||||
if proto is None:
|
||||
continue
|
||||
if support is None or float(support) <= 0.0:
|
||||
continue
|
||||
protos.append(np.asarray(proto, dtype=np.float64))
|
||||
supports.append(float(support))
|
||||
if protos:
|
||||
out[int(class_id)] = (protos, supports)
|
||||
return out
|
||||
|
||||
|
||||
def _weighted_mean(protos, weights):
|
||||
w = np.asarray(weights, dtype=np.float64)
|
||||
total = float(w.sum())
|
||||
if not math.isfinite(total) or total <= 0.0:
|
||||
raise ValueError("weights must sum to a positive finite value")
|
||||
w = w / total
|
||||
mat = np.stack(protos)
|
||||
return (w[:, None] * mat).sum(axis=0)
|
||||
|
||||
|
||||
def _normalised_power(supports, beta):
|
||||
n = np.asarray(supports, dtype=np.float64)
|
||||
if np.any(~np.isfinite(n)) or np.any(n <= 0):
|
||||
raise ValueError("supports must be strictly positive and finite")
|
||||
w = n ** float(beta)
|
||||
return w / w.sum()
|
||||
|
||||
|
||||
def aggregate_variant(
|
||||
contributions: Mapping[int, Sequence],
|
||||
mode,
|
||||
*,
|
||||
beta=None,
|
||||
shrink_lambda: float = 0.5,
|
||||
cap_factor: float = 4.0,
|
||||
min_support: float = 10.0,
|
||||
):
|
||||
"""Aggregate one round's per-class contributions under *mode*.
|
||||
|
||||
``contributions`` maps ``class_id -> [(C_ij, N_ij), ...]`` exactly like
|
||||
:func:`protean_research.aggregation.aggregate_class_prototypes`.
|
||||
"""
|
||||
if mode in BASELINE_MODES:
|
||||
# Unchanged project behaviour; beta semantics are also the project's.
|
||||
return aggregate_class_prototypes(contributions, mode, beta=beta)
|
||||
|
||||
if mode not in VARIANT_MODES:
|
||||
raise ValueError(f"unknown aggregation mode {mode!r}")
|
||||
if beta is None:
|
||||
raise ValueError(f"{mode} requires beta")
|
||||
beta = float(beta)
|
||||
if not math.isfinite(beta) or beta < 0.0:
|
||||
raise ValueError(f"beta must be finite and >= 0, got {beta}")
|
||||
|
||||
collected = _collect(contributions)
|
||||
result = {}
|
||||
for class_id, (protos, supports) in collected.items():
|
||||
n = np.asarray(supports, dtype=np.float64)
|
||||
if mode == "v_beta":
|
||||
if beta > 2.0:
|
||||
raise ValueError("v_beta beta must be <= 2.0")
|
||||
w = n ** beta
|
||||
elif mode == "v_shrink":
|
||||
if not 0.0 <= shrink_lambda <= 1.0:
|
||||
raise ValueError("shrink_lambda must lie in [0, 1]")
|
||||
p = _normalised_power(n, beta)
|
||||
w = (1.0 - shrink_lambda) / len(protos) + shrink_lambda * p
|
||||
elif mode == "v_cap":
|
||||
if cap_factor < 1.0:
|
||||
raise ValueError("cap_factor must be >= 1")
|
||||
raw = n ** beta
|
||||
med = float(np.median(raw))
|
||||
w = np.minimum(raw, cap_factor * med)
|
||||
elif mode == "v_minsup":
|
||||
keep = n >= float(min_support)
|
||||
if not np.any(keep):
|
||||
# Documented fallback: never emit an empty class. If every
|
||||
# contributor is below the threshold, keep all of them and
|
||||
# fall back to equal weighting.
|
||||
keep = np.ones_like(n, dtype=bool)
|
||||
sub = [p for p, k in zip(protos, keep) if k]
|
||||
w = np.ones(len(sub), dtype=np.float64)
|
||||
protos = sub
|
||||
elif mode == "v_logweight":
|
||||
w = np.log1p(n)
|
||||
else: # pragma: no cover
|
||||
raise AssertionError(mode)
|
||||
if not np.any(w > 0):
|
||||
w = np.ones(len(protos), dtype=np.float64)
|
||||
result[int(class_id)] = _weighted_mean(protos, w).astype(np.float64).tolist()
|
||||
return result
|
||||
|
||||
|
||||
def aggregate_from_client_dicts(
|
||||
client_prototypes,
|
||||
client_supports,
|
||||
num_classes: int,
|
||||
mode,
|
||||
**kwargs,
|
||||
):
|
||||
"""Adapter with the same signature as the project server aggregator."""
|
||||
contributions = {c: [] for c in range(num_classes)}
|
||||
for prototypes, supports in zip(client_prototypes, client_supports):
|
||||
for class_id, proto in prototypes.items():
|
||||
contributions[int(class_id)].append(
|
||||
(proto, supports.get(int(class_id), 0))
|
||||
)
|
||||
return aggregate_variant(contributions, mode, **kwargs)
|
||||
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python
|
||||
"""Read-only pre-flight/verification checks for exploration_v2."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
EXPL = REPO / "exploration_v2"
|
||||
|
||||
|
||||
def sh(cmd):
|
||||
r = subprocess.run(cmd, cwd=str(REPO), capture_output=True, text=True)
|
||||
return r.returncode, r.stdout.strip(), r.stderr.strip()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
checks = []
|
||||
|
||||
def add(name, ok, detail=""):
|
||||
checks.append({"check": name, "ok": bool(ok), "detail": detail})
|
||||
|
||||
plan = (EXPL / "PLAN.md").read_bytes()
|
||||
h = hashlib.sha256(plan).hexdigest()
|
||||
rec = (EXPL / "PLAN.sha256").read_text().splitlines()
|
||||
add("plan_hash_matches", rec and rec[0].startswith(h), f"{h}")
|
||||
|
||||
rc, out, err = sh(["git", "status", "--porcelain"])
|
||||
tracked = [line for line in out.splitlines()
|
||||
if not line.startswith("?? exploration_v2/")
|
||||
and "RESTORE_VERIFICATION_REPORT.md" not in line]
|
||||
add("no_tracked_modifications", rc == 0 and not tracked, "|".join(tracked[:5]))
|
||||
|
||||
rc, out, err = sh(["git", "status", "--porcelain", "planningawal/"])
|
||||
add("planningawal_unchanged", out == "", out)
|
||||
|
||||
raw = list(REPO.glob("**/5G-NIDD.csv")) + list(REPO.glob("**/X-IIoTID-dataset.csv"))
|
||||
raw = [p for p in raw if ".venv" not in str(p)]
|
||||
add("no_raw_dataset_in_repo", not raw, "|".join(str(p) for p in raw[:3]))
|
||||
|
||||
rc, out, err = sh([str(REPO / ".venv/bin/python"), "-m", "pytest", "-q",
|
||||
"-p", "no:cacheprovider"])
|
||||
add("original_tests_pass", rc == 0, out.splitlines()[-1] if out else err[-200:])
|
||||
|
||||
rc, out, err = sh([str(REPO / ".venv/bin/python"), "-m", "pytest",
|
||||
str(EXPL / "tests"), "-q", "-p", "no:cacheprovider"])
|
||||
add("variant_tests_pass", rc == 0, out.splitlines()[-1] if out else err[-200:])
|
||||
|
||||
seeds = set()
|
||||
if (REPO / "results").is_dir():
|
||||
for p in (REPO / "results").glob("*seed*"):
|
||||
name = p.name
|
||||
for part in name.split("__"):
|
||||
if part.startswith("seed"):
|
||||
try:
|
||||
seeds.add(int(part[4:]))
|
||||
except ValueError:
|
||||
pass
|
||||
add("confirm_seeds_new", not ({3, 4} & seeds), f"restored seeds={sorted(seeds)}")
|
||||
|
||||
for p in (EXPL / "partitions").glob("*.json"):
|
||||
m = json.loads(p.read_text())
|
||||
if m.get("seed") in (3, 4):
|
||||
add(f"manifest_ok_{p.name}", m.get("num_clients") == 10 and
|
||||
len(m.get("support", [])) == 10, f"seed={m.get('seed')}")
|
||||
|
||||
ok = all(c["ok"] for c in checks)
|
||||
lines = ["# exploration_v2 setup check\n\n",
|
||||
f"Generated: {__import__('datetime').datetime.utcnow().isoformat()}Z\n\n",
|
||||
"| check | result | detail |\n|---|---|---|\n"]
|
||||
for c in checks:
|
||||
lines.append(f"| {c['check']} | {'PASS' if c['ok'] else 'FAIL'} | {c['detail']} |\n")
|
||||
lines.append(f"\nOverall: {'PASS' if ok else 'FAIL'}\n")
|
||||
(EXPL / "SETUP_CHECK.md").write_text("".join(lines), encoding="utf-8")
|
||||
print(json.dumps({"overall": "PASS" if ok else "FAIL", "checks": checks}, indent=2))
|
||||
return 0 if ok else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"started_utc": "2026-10-30T04:10:46Z",
|
||||
"tolerance": 0.001,
|
||||
"runs": {
|
||||
"base": {
|
||||
"mode": "original_protean",
|
||||
"beta": null,
|
||||
"extra": [],
|
||||
"returncode": 0,
|
||||
"val_rare_macro_f1": 0.3506859881859882,
|
||||
"results_dir": "exploration_v2/smoke/results/xiiotid__alpha0.25__seed0__smoke_base"
|
||||
},
|
||||
"beta0": {
|
||||
"mode": "support_weighted",
|
||||
"beta": 0.0,
|
||||
"extra": [],
|
||||
"returncode": 0,
|
||||
"val_rare_macro_f1": 0.3506859881859882,
|
||||
"results_dir": "exploration_v2/smoke/results/xiiotid__alpha0.25__seed0__smoke_beta0"
|
||||
},
|
||||
"beta1": {
|
||||
"mode": "support_weighted",
|
||||
"beta": 1.0,
|
||||
"extra": [],
|
||||
"returncode": 0,
|
||||
"val_rare_macro_f1": 0.10617431010522135,
|
||||
"results_dir": "exploration_v2/smoke/results/xiiotid__alpha0.25__seed0__smoke_beta1"
|
||||
},
|
||||
"v_beta1.5": {
|
||||
"mode": "v_beta",
|
||||
"beta": 1.5,
|
||||
"extra": [],
|
||||
"returncode": 0,
|
||||
"val_rare_macro_f1": 0.0014492753623188406,
|
||||
"results_dir": "exploration_v2/smoke/results/xiiotid__alpha0.25__seed0__smoke_v_beta1.5"
|
||||
},
|
||||
"v_shrink": {
|
||||
"mode": "v_shrink",
|
||||
"beta": 1.0,
|
||||
"extra": [
|
||||
"--shrink-lambda",
|
||||
"0.5"
|
||||
],
|
||||
"returncode": 0,
|
||||
"val_rare_macro_f1": 0.07774294670846396,
|
||||
"results_dir": "exploration_v2/smoke/results/xiiotid__alpha0.25__seed0__smoke_v_shrink"
|
||||
},
|
||||
"v_cap4": {
|
||||
"mode": "v_cap",
|
||||
"beta": 1.0,
|
||||
"extra": [
|
||||
"--cap-factor",
|
||||
"4"
|
||||
],
|
||||
"returncode": 0,
|
||||
"val_rare_macro_f1": 0.09021243192856791,
|
||||
"results_dir": "exploration_v2/smoke/results/xiiotid__alpha0.25__seed0__smoke_v_cap4"
|
||||
},
|
||||
"v_cap2": {
|
||||
"mode": "v_cap",
|
||||
"beta": 1.0,
|
||||
"extra": [
|
||||
"--cap-factor",
|
||||
"2"
|
||||
],
|
||||
"returncode": 0,
|
||||
"val_rare_macro_f1": 0.11728240313145973,
|
||||
"results_dir": "exploration_v2/smoke/results/xiiotid__alpha0.25__seed0__smoke_v_cap2"
|
||||
},
|
||||
"v_minsup": {
|
||||
"mode": "v_minsup",
|
||||
"beta": 0.0,
|
||||
"extra": [
|
||||
"--min-support",
|
||||
"10"
|
||||
],
|
||||
"returncode": 0,
|
||||
"val_rare_macro_f1": 0.09491525423728812,
|
||||
"results_dir": "exploration_v2/smoke/results/xiiotid__alpha0.25__seed0__smoke_v_minsup"
|
||||
},
|
||||
"v_logweight": {
|
||||
"mode": "v_logweight",
|
||||
"beta": 0.0,
|
||||
"extra": [],
|
||||
"returncode": 0,
|
||||
"val_rare_macro_f1": 0.18652998776009794,
|
||||
"results_dir": "exploration_v2/smoke/results/xiiotid__alpha0.25__seed0__smoke_v_logweight"
|
||||
}
|
||||
},
|
||||
"pytest_returncode": 0,
|
||||
"pytest_tail": [
|
||||
"........... [100%]"
|
||||
],
|
||||
"equivalence_checks": {
|
||||
"beta0": 0.0,
|
||||
"beta0_within_tolerance": true
|
||||
},
|
||||
"verdict": "PASS",
|
||||
"finished_utc": "2026-10-30T04:11:54Z"
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"algorithm": "per_class_dirichlet_multinomial",
|
||||
"alpha": 0.25,
|
||||
"benign_class": "Normal",
|
||||
"class_names": [
|
||||
"C&C",
|
||||
"Exfiltration",
|
||||
"Exploitation",
|
||||
"Lateral_movement",
|
||||
"Normal",
|
||||
"RDOS",
|
||||
"Reconnaissance",
|
||||
"Tampering",
|
||||
"Weaponization"
|
||||
],
|
||||
"config_hash": null,
|
||||
"created_utc": "2026-10-30T04:01:46Z",
|
||||
"dataset": "xiiotid",
|
||||
"dataset_name": "X-IIoTID",
|
||||
"manifest_version": "1",
|
||||
"num_classes": 9,
|
||||
"num_clients": 4,
|
||||
"num_train": 2098,
|
||||
"partition_hash": "9ac08797480badf66493b2ea557a1f8fd3adfcd190217e1d8fe6ce4accedb3e6",
|
||||
"preprocessing_hash": "9adc542272436f89b3dfd3285bd6b73427c3f2c1a66caf7da95cd1962cc6ec7b",
|
||||
"python": "3.12.3",
|
||||
"rng_seed": 1617371214,
|
||||
"seed": 0,
|
||||
"split": {
|
||||
"hash": "79e21dfb1bb8fa9076e8c24ea14cef409ee702be85c3ab86fc4ccb24fe0e6cb7",
|
||||
"seed": 0,
|
||||
"sizes": {
|
||||
"test": 599,
|
||||
"train": 2098,
|
||||
"validation": 300
|
||||
},
|
||||
"strategy": "stratified_by_class",
|
||||
"test_fraction": 0.2,
|
||||
"train_fraction": 0.7,
|
||||
"validation_fraction": 0.1
|
||||
},
|
||||
"support": [
|
||||
[
|
||||
4,
|
||||
34,
|
||||
3,
|
||||
1,
|
||||
381,
|
||||
0,
|
||||
0,
|
||||
12,
|
||||
3
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
121,
|
||||
0,
|
||||
0,
|
||||
38
|
||||
],
|
||||
[
|
||||
0,
|
||||
4,
|
||||
0,
|
||||
89,
|
||||
450,
|
||||
7,
|
||||
327,
|
||||
0,
|
||||
151
|
||||
],
|
||||
[
|
||||
3,
|
||||
11,
|
||||
0,
|
||||
4,
|
||||
236,
|
||||
216,
|
||||
0,
|
||||
0,
|
||||
3
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"algorithm": "per_class_dirichlet_multinomial",
|
||||
"alpha": 0.5,
|
||||
"benign_class": "Normal",
|
||||
"class_names": [
|
||||
"C&C",
|
||||
"Exfiltration",
|
||||
"Exploitation",
|
||||
"Lateral_movement",
|
||||
"Normal",
|
||||
"RDOS",
|
||||
"Reconnaissance",
|
||||
"Tampering",
|
||||
"Weaponization"
|
||||
],
|
||||
"config_hash": null,
|
||||
"created_utc": "2026-10-30T03:57:20Z",
|
||||
"dataset": "xiiotid",
|
||||
"dataset_name": "X-IIoTID",
|
||||
"manifest_version": "1",
|
||||
"num_classes": 9,
|
||||
"num_clients": 4,
|
||||
"num_train": 2798,
|
||||
"partition_hash": "81600a44982bd77e32c0897aa9c367835ef5c8a3c651eb30f2b3e2862cc06a47",
|
||||
"preprocessing_hash": "83d50d3adb93dd6b6f82e9c9395d9d4b28c30c7a783034508496988f6eddf077",
|
||||
"python": "3.12.3",
|
||||
"rng_seed": 2009062324,
|
||||
"seed": 0,
|
||||
"split": {
|
||||
"hash": "f5370ac857a1b4463eb26b0f06a446a6235c008d0fa772019cf11a8d32f2eaf0",
|
||||
"seed": 0,
|
||||
"sizes": {
|
||||
"test": 800,
|
||||
"train": 2798,
|
||||
"validation": 399
|
||||
},
|
||||
"strategy": "stratified_by_class",
|
||||
"test_fraction": 0.2,
|
||||
"train_fraction": 0.7,
|
||||
"validation_fraction": 0.1
|
||||
},
|
||||
"support": [
|
||||
[
|
||||
7,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
65,
|
||||
15,
|
||||
0,
|
||||
0,
|
||||
138
|
||||
],
|
||||
[
|
||||
1,
|
||||
47,
|
||||
1,
|
||||
1,
|
||||
132,
|
||||
330,
|
||||
292,
|
||||
10,
|
||||
68
|
||||
],
|
||||
[
|
||||
2,
|
||||
14,
|
||||
1,
|
||||
63,
|
||||
13,
|
||||
56,
|
||||
55,
|
||||
6,
|
||||
22
|
||||
],
|
||||
[
|
||||
0,
|
||||
18,
|
||||
0,
|
||||
33,
|
||||
1246,
|
||||
101,
|
||||
47,
|
||||
5,
|
||||
6
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"attempts": {
|
||||
"xiiotid__alpha0.25__seed3__v_cap__b1__c4": 1,
|
||||
"xiiotid__alpha0.25__seed3__v_shrink__b1__lam0.5": 1
|
||||
},
|
||||
"budget_start_utc": "2026-10-30T04:11:55Z",
|
||||
"max_procs": 2,
|
||||
"notes": [
|
||||
"2026-10-31T08:35Z recovery: 2 OOM-killed seed4 reference runs requeued at max_procs=2",
|
||||
"2026-10-31T14:12Z recovery A5: unit-name collision on retries fixed; seed4 refs requeued"
|
||||
],
|
||||
"phase": "done",
|
||||
"ranking_frozen": true,
|
||||
"recent_exits": [
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"screening_started": false,
|
||||
"terminal_failed": []
|
||||
}
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# Quick exploration_v2 status (returns in well under 60 s).
|
||||
set -uo pipefail
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$HERE/.." && pwd)"
|
||||
|
||||
"$REPO_ROOT/.venv/bin/python" "$HERE/scripts/status_table.py"
|
||||
echo
|
||||
if [ -f "$HERE/HEARTBEAT" ]; then
|
||||
echo "heartbeat file age: $(( $(date +%s) - $(stat -c %Y "$HERE/HEARTBEAT") )) s"
|
||||
fi
|
||||
echo "driver scope:"
|
||||
systemctl --user list-units --type=scope --no-legend 2>/dev/null | grep -i explorev2 || true
|
||||
echo "queue sizes: screen=$(($(wc -l < "$HERE/queue_screen.csv" 2>/dev/null || echo 1) - 1)) confirm=$( [ -f "$HERE/queue_confirm.csv" ] && echo $(( $(wc -l < "$HERE/queue_confirm.csv") - 1 )) || echo 0 )"
|
||||
@@ -0,0 +1,35 @@
|
||||
config,dataset,alpha,beta,seed,aggregation_mode,status,wall_s,cpu_user_s,cpu_sys_s,percent_cpu,peak_rss_kb,exit_code,started_utc,ended_utc,run_dir,log_dir,notes
|
||||
xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5,xiiotid,0.25,1.0,0,v_shrink,completed,10965.00,10331.62,629.68,99,8788104,0,2026-10-30T04:11:55Z,2026-10-30T07:14:40Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_shrink__b1__lam0.5/logs,
|
||||
xiiotid__alpha0.25__seed0__v_cap__b1__c4,xiiotid,0.25,1.0,0,v_cap,completed,11022.00,10392.67,626.13,99,8789080,0,2026-10-30T04:11:55Z,2026-10-30T07:15:37Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_cap__b1__c4,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_cap__b1__c4/logs,
|
||||
xiiotid__alpha0.25__seed0__v_beta__b1.5,xiiotid,0.25,1.5,0,v_beta,completed,11048.00,10424.25,620.24,99,8788696,0,2026-10-30T04:11:55Z,2026-10-30T07:16:03Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_beta__b1.5,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_beta__b1.5/logs,
|
||||
xiiotid__alpha0.25__seed0__original_protean,xiiotid,0.25,0,0,original_protean,completed,10879.00,10141.92,628.62,98,8788432,0,2026-10-30T07:14:43Z,2026-10-30T10:16:03Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__original_protean,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__original_protean/logs,
|
||||
xiiotid__alpha0.25__seed0__v_minsup__t10,xiiotid,0.25,0.0,0,v_minsup,completed,10904.00,10156.27,630.54,98,8788056,0,2026-10-30T07:16:06Z,2026-10-30T10:17:50Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_minsup__t10,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_minsup__t10/logs,
|
||||
xiiotid__alpha0.25__seed0__v_cap__b1__c2,xiiotid,0.25,1.0,0,v_cap,completed,10960.00,10217.02,625.13,98,8787984,0,2026-10-30T07:15:45Z,2026-10-30T10:18:26Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_cap__b1__c2,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_cap__b1__c2/logs,
|
||||
xiiotid__alpha0.25__seed0__v_logweight,xiiotid,0.25,0.0,0,v_logweight,completed,10645.00,10013.81,627.86,99,8787588,0,2026-10-30T10:16:12Z,2026-10-30T13:13:38Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_logweight,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed0__v_logweight/logs,
|
||||
5gnidd__alpha0.5__seed0__original_protean,5gnidd,0.5,0,0,original_protean,completed,16807.00,15709.29,1094.58,99,10800928,0,2026-10-30T10:18:28Z,2026-10-30T14:58:36Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__original_protean,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__original_protean/logs,
|
||||
5gnidd__alpha0.5__seed0__v_beta__b1.5,5gnidd,0.5,1.5,0,v_beta,completed,17571.00,16433.69,1133.44,99,10787996,0,2026-10-30T13:13:46Z,2026-10-30T18:06:38Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_beta__b1.5,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_beta__b1.5/logs,
|
||||
5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5,5gnidd,0.5,1.0,0,v_shrink,completed,17467.00,16353.62,1108.69,99,10791372,0,2026-10-30T14:58:45Z,2026-10-30T19:49:52Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_shrink__b1__lam0.5/logs,
|
||||
5gnidd__alpha0.5__seed0__v_cap__b1__c4,5gnidd,0.5,1.0,0,v_cap,completed,16374.00,15305.03,1064.96,99,10795492,0,2026-10-30T18:06:47Z,2026-10-30T22:39:42Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_cap__b1__c4,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_cap__b1__c4/logs,
|
||||
5gnidd__alpha0.5__seed0__v_cap__b1__c2,5gnidd,0.5,1.0,0,v_cap,completed,15875.00,14852.73,1018.36,99,10794444,0,2026-10-30T19:50:02Z,2026-10-31T00:14:37Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_cap__b1__c2,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_cap__b1__c2/logs,
|
||||
5gnidd__alpha0.5__seed0__v_minsup__t10,5gnidd,0.5,0.0,0,v_minsup,completed,16232.00,15203.43,1021.85,99,10787860,0,2026-10-30T22:39:52Z,2026-10-31T03:10:24Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_minsup__t10,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_minsup__t10/logs,
|
||||
5gnidd__alpha0.5__seed0__v_logweight,5gnidd,0.5,0.0,0,v_logweight,completed,17342.00,16248.83,1085.02,99,10806700,0,2026-10-31T00:14:45Z,2026-10-31T05:03:48Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_logweight,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed0__v_logweight/logs,
|
||||
xiiotid__alpha0.25__seed3__original_protean,xiiotid,0.25,0,3,original_protean,completed,11102.00,10505.16,593.52,99,10986852,0,2026-10-31T05:07:30Z,2026-10-31T08:12:32Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed3__original_protean,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed3__original_protean/logs,
|
||||
xiiotid__alpha0.25__seed3__support_weighted__beta0.5,xiiotid,0.25,0.5,3,support_weighted,completed,11105.00,10503.16,599.06,99,10986972,0,2026-10-31T05:07:30Z,2026-10-31T08:12:36Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed3__support_weighted__beta0.5,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed3__support_weighted__beta0.5/logs,
|
||||
xiiotid__alpha0.25__seed3__support_weighted__beta1,xiiotid,0.25,1,3,support_weighted,completed,11247.00,10628.09,615.51,99,10986812,0,2026-10-31T05:07:30Z,2026-10-31T08:14:57Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed3__support_weighted__beta1,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed3__support_weighted__beta1/logs,
|
||||
xiiotid__alpha0.25__seed4__original_protean,xiiotid,0.25,0,4,original_protean,completed,11200.00,10544.02,652.44,99,13373900,0,2026-10-31T14:09:18Z,2026-10-31T17:15:59Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed4__original_protean,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed4__original_protean/logs,
|
||||
xiiotid__alpha0.25__seed4__support_weighted__beta0.5,xiiotid,0.25,0.5,4,support_weighted,completed,11147.00,10490.48,653.41,99,13376792,0,2026-10-31T14:09:18Z,2026-10-31T17:15:06Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed4__support_weighted__beta0.5,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed4__support_weighted__beta0.5/logs,
|
||||
xiiotid__alpha0.25__seed4__support_weighted__beta1,xiiotid,0.25,1,4,support_weighted,completed,11529.00,10850.72,675.30,99,13377304,0,2026-10-31T17:15:10Z,2026-10-31T20:27:20Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed4__support_weighted__beta1,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed4__support_weighted__beta1/logs,
|
||||
xiiotid__alpha0.25__seed3__v_cap__b1__c4,xiiotid,0.25,1.0,3,v_cap,completed,10621.00,10020.19,598.36,99,10986660,0,2026-10-31T11:09:05Z,2026-10-31T14:06:08Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed3__v_cap__b1__c4,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed3__v_cap__b1__c4/logs,
|
||||
xiiotid__alpha0.25__seed3__v_shrink__b1__lam0.5,xiiotid,0.25,1.0,3,v_shrink,completed,10678.00,10077.25,599.26,99,10986572,0,2026-10-31T11:09:48Z,2026-10-31T14:07:47Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed3__v_shrink__b1__lam0.5,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed3__v_shrink__b1__lam0.5/logs,
|
||||
xiiotid__alpha0.25__seed4__v_shrink__b1__lam0.5,xiiotid,0.25,1.0,4,v_shrink,completed,11448.00,10782.09,663.27,99,13377596,0,2026-10-31T17:16:03Z,2026-10-31T20:26:52Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed4__v_shrink__b1__lam0.5,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed4__v_shrink__b1__lam0.5/logs,
|
||||
xiiotid__alpha0.25__seed4__v_cap__b1__c4,xiiotid,0.25,1.0,4,v_cap,completed,10168.00,9580.67,584.50,99,13377208,0,2026-10-31T20:27:02Z,2026-10-31T23:16:30Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed4__v_cap__b1__c4,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/xiiotid__alpha0.25__seed4__v_cap__b1__c4/logs,
|
||||
5gnidd__alpha0.5__seed3__original_protean,5gnidd,0.5,0,3,original_protean,completed,15875.00,14911.46,960.26,99,9482756,0,2026-10-31T20:27:23Z,2026-11-01T00:51:58Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed3__original_protean,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed3__original_protean/logs,
|
||||
5gnidd__alpha0.5__seed3__support_weighted__beta0.5,5gnidd,0.5,0.5,3,support_weighted,completed,16116.00,15128.78,983.96,99,9507836,0,2026-10-31T23:16:40Z,2026-11-01T03:45:16Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed3__support_weighted__beta0.5,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed3__support_weighted__beta0.5/logs,
|
||||
5gnidd__alpha0.5__seed3__support_weighted__beta1,5gnidd,0.5,1,3,support_weighted,completed,16782.00,15774.09,1004.24,99,9480524,0,2026-11-01T00:52:06Z,2026-11-01T05:31:49Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed3__support_weighted__beta1,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed3__support_weighted__beta1/logs,
|
||||
5gnidd__alpha0.5__seed3__v_shrink__b1__lam0.5,5gnidd,0.5,1.0,3,v_shrink,completed,16459.00,15453.75,1000.89,99,9501568,0,2026-11-01T03:45:24Z,2026-11-01T08:19:43Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed3__v_shrink__b1__lam0.5,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed3__v_shrink__b1__lam0.5/logs,
|
||||
5gnidd__alpha0.5__seed3__v_cap__b1__c4,5gnidd,0.5,1.0,3,v_cap,completed,17023.00,15980.81,1039.03,99,9487356,0,2026-11-01T05:31:54Z,2026-11-01T10:15:38Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed3__v_cap__b1__c4,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed3__v_cap__b1__c4/logs,
|
||||
5gnidd__alpha0.5__seed4__original_protean,5gnidd,0.5,0,4,original_protean,completed,17324.00,16219.34,1100.77,99,11657012,0,2026-11-01T08:19:51Z,2026-11-01T13:08:35Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed4__original_protean,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed4__original_protean/logs,
|
||||
5gnidd__alpha0.5__seed4__support_weighted__beta0.5,5gnidd,0.5,0.5,4,support_weighted,completed,17181.00,16103.55,1073.60,99,11697428,0,2026-11-01T10:15:40Z,2026-11-01T15:02:03Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed4__support_weighted__beta0.5,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed4__support_weighted__beta0.5/logs,
|
||||
5gnidd__alpha0.5__seed4__support_weighted__beta1,5gnidd,0.5,1,4,support_weighted,completed,17582.00,16447.80,1131.04,99,11669892,0,2026-11-01T13:08:37Z,2026-11-01T18:01:41Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed4__support_weighted__beta1,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed4__support_weighted__beta1/logs,
|
||||
5gnidd__alpha0.5__seed4__v_shrink__b1__lam0.5,5gnidd,0.5,1.0,4,v_shrink,completed,17234.00,16097.43,1133.25,99,11688404,0,2026-11-01T15:02:11Z,2026-11-01T19:49:27Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed4__v_shrink__b1__lam0.5,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed4__v_shrink__b1__lam0.5/logs,
|
||||
5gnidd__alpha0.5__seed4__v_cap__b1__c4,5gnidd,0.5,1.0,4,v_cap,completed,16415.00,15378.21,1031.38,99,11679488,0,2026-11-01T18:01:52Z,2026-11-01T22:35:27Z,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed4__v_cap__b1__c4,/home/willtanoe/project/prototype-agregation/exploration_v2/results/runs/5gnidd__alpha0.5__seed4__v_cap__b1__c4/logs,
|
||||
|
@@ -0,0 +1,124 @@
|
||||
"""Fixture tests for the screening ranking and post-confirmation analysis.
|
||||
|
||||
These use a temporary directory tree and never read or write the live
|
||||
``exploration_v2/results`` or any restored result. The references for the
|
||||
fixture come from the real restored grid, read-only.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import hashlib
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
sys.path.insert(0, str(REPO / "exploration_v2" / "scripts"))
|
||||
|
||||
import rank_screening # noqa: E402
|
||||
import analyze_results # noqa: E402
|
||||
|
||||
|
||||
def _write(path: Path, payload):
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(payload), encoding="utf-8")
|
||||
|
||||
|
||||
def _screen_fixture(tmp: Path):
|
||||
base = {"S1": 0.60, "S2": 0.85}
|
||||
labels = [("v_beta__b1.5", 0.01), ("v_shrink__b1__lam0.5", 0.02),
|
||||
("v_cap__b1__c4", 0.015), ("v_cap__b1__c2", -0.01),
|
||||
("v_minsup__t10", -0.02), ("v_logweight", 0.005)]
|
||||
rows = []
|
||||
for ds, alpha, cid in (("xiiotid", 0.25, "S1"), ("5gnidd", 0.5, "S2")):
|
||||
for label, off in labels:
|
||||
rid = f"{ds}__alpha{alpha:g}__seed0__{label}"
|
||||
d = tmp / "runs" / rid / "results" / rid
|
||||
_write(d / "val_global_metrics.json",
|
||||
{"rare_class_macro_f1": base[cid] + off})
|
||||
_write(d / "val_selection.json",
|
||||
{"val_rare_class_macro_f1_per_client_mean": 0.5 + off})
|
||||
# A decoy test file: the ranking must never open it.
|
||||
_write(d / "test_global_metrics.json", {"rare_class_macro_f1": 999.0})
|
||||
rows.append(dict(run_id=rid, dataset=ds, alpha=str(alpha), seed="0",
|
||||
mode="v_beta", beta="1", shrink="", cap="",
|
||||
minsup="", part_dir="x", label=label))
|
||||
q = tmp / "queue_screen.csv"
|
||||
with q.open("w", newline="", encoding="utf-8") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=list(rows[0]))
|
||||
w.writeheader()
|
||||
w.writerows(rows)
|
||||
return q
|
||||
|
||||
|
||||
def test_rank_uses_validation_only(tmp_path, monkeypatch):
|
||||
q = _screen_fixture(tmp_path)
|
||||
monkeypatch.setattr(rank_screening, "RUNS", tmp_path / "runs")
|
||||
monkeypatch.setattr(rank_screening, "SCREEN", q)
|
||||
monkeypatch.setattr(rank_screening, "ACCESS", tmp_path / "ACCESS_LOG.txt")
|
||||
monkeypatch.setattr(rank_screening, "OUT", tmp_path / "ranking.json")
|
||||
assert rank_screening.main() == 0
|
||||
payload = json.loads((tmp_path / "ranking.json").read_text())
|
||||
assert payload["top2"] == ["v_shrink__b1__lam0.5", "v_cap__b1__c4"]
|
||||
log = (tmp_path / "ACCESS_LOG.txt").read_text()
|
||||
assert "test_global_metrics" not in log
|
||||
assert "per_client.csv" not in log
|
||||
|
||||
|
||||
def test_analysis_refuses_without_freeze(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(analyze_results, "EXPL", tmp_path)
|
||||
monkeypatch.setattr(analyze_results, "RUNS", tmp_path / "runs")
|
||||
monkeypatch.setattr(analyze_results, "OUT", tmp_path / "analysis")
|
||||
with pytest.raises(SystemExit):
|
||||
analyze_results.main()
|
||||
|
||||
|
||||
def _confirm_fixture(tmp: Path, top2):
|
||||
rows = []
|
||||
for ds, alpha in (("xiiotid", 0.25), ("5gnidd", 0.5)):
|
||||
for seed in (3, 4):
|
||||
for label, val in [("original_protean", 0.60),
|
||||
("support_weighted__beta0.5", 0.61),
|
||||
("support_weighted__beta1", 0.605),
|
||||
(top2[0], 0.62), (top2[1], 0.615)]:
|
||||
rid = f"{ds}__alpha{alpha:g}__seed{seed}__{label}"
|
||||
d = tmp / "runs" / rid / "results" / rid
|
||||
_write(d / "val_global_metrics.json",
|
||||
{"rare_class_macro_f1": val, "rare_class_recall": 0.8,
|
||||
"macro_f1": 0.7})
|
||||
_write(d / "val_selection.json",
|
||||
{"val_rare_class_macro_f1_per_client_mean": val - 0.05})
|
||||
_write(d / "test_global_metrics.json",
|
||||
{"rare_class_macro_f1": val + 0.01,
|
||||
"rare_class_recall": 0.8, "macro_f1": 0.7})
|
||||
rows.append(dict(run_id=rid, dataset=ds, alpha=str(alpha),
|
||||
seed=str(seed), mode="x", beta="", shrink="",
|
||||
cap="", minsup="", part_dir="x", label=label))
|
||||
q = tmp / "queue_confirm.csv"
|
||||
with q.open("w", newline="", encoding="utf-8") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=list(rows[0]))
|
||||
w.writeheader()
|
||||
w.writerows(rows)
|
||||
(tmp / "queue_screen.csv").write_text(
|
||||
"run_id,dataset,alpha,seed,mode,beta,shrink,cap,minsup,part_dir,label\n")
|
||||
return top2
|
||||
|
||||
|
||||
def test_analysis_writes_tables(tmp_path, monkeypatch):
|
||||
top2 = ["v_shrink__b1__lam0.5", "v_cap__b1__c4"]
|
||||
_confirm_fixture(tmp_path, top2)
|
||||
ranking = {"top2": top2, "candidates": [], "current_method_reference": {}}
|
||||
(tmp_path / "ranking.json").write_text(json.dumps(ranking))
|
||||
h = hashlib.sha256((tmp_path / "ranking.json").read_bytes()).hexdigest()
|
||||
(tmp_path / "ranking.sha256").write_text(f"{h} ranking.json\n2026-01-01T00:00:00Z\n")
|
||||
monkeypatch.setattr(analyze_results, "EXPL", tmp_path)
|
||||
monkeypatch.setattr(analyze_results, "RUNS", tmp_path / "runs")
|
||||
monkeypatch.setattr(analyze_results, "OUT", tmp_path / "analysis")
|
||||
assert analyze_results.main() == 0
|
||||
summary = list(csv.DictReader(open(tmp_path / "analysis" / "confirm_summary.csv")))
|
||||
assert len(summary) == 2
|
||||
assert summary[0]["positive_pairs_val_vs_original"] == "4"
|
||||
assert (tmp_path / "REPORT_DATA.md").is_file()
|
||||
@@ -0,0 +1,160 @@
|
||||
"""Unit tests for the exploration_v2 aggregation variants.
|
||||
|
||||
The critical invariants required before any expensive run:
|
||||
|
||||
* ``original_protean`` is bit-for-bit the project implementation;
|
||||
* ``support_weighted`` (including beta = 0) delegates to the project code;
|
||||
* ``v_beta`` at beta = 0 reproduces the equal mean, and at beta = 1 reproduces
|
||||
``support_weighted`` beta = 1;
|
||||
* a single contributor, equal supports and missing classes behave as documented;
|
||||
* every variant returns finite, deterministic vectors.
|
||||
|
||||
Run with:
|
||||
.venv/bin/python -m pytest exploration_v2/tests -q
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
sys.path.insert(0, str(REPO / "src"))
|
||||
sys.path.insert(0, str(REPO / "exploration_v2" / "scripts"))
|
||||
|
||||
from protean_research.aggregation import aggregate_class_prototypes # noqa: E402
|
||||
import variants as V # noqa: E402
|
||||
|
||||
|
||||
def _fixture():
|
||||
rng = np.random.default_rng(7)
|
||||
# class 0: 4 contributors; class 1: 2 contributors; class 2 absent
|
||||
return {
|
||||
0: [(rng.normal(size=8), n) for n in (5, 50, 500, 5000)],
|
||||
1: [(rng.normal(size=8), 3), (rng.normal(size=8), 300)],
|
||||
}, rng
|
||||
|
||||
|
||||
def _mean(protos):
|
||||
return np.mean(np.stack([np.asarray(p, float) for p in protos]), axis=0)
|
||||
|
||||
|
||||
def test_original_is_project_implementation():
|
||||
contributions, _ = _fixture()
|
||||
got = V.aggregate_variant(contributions, "original_protean")
|
||||
ref = aggregate_class_prototypes(contributions, "original_protean")
|
||||
assert set(got) == set(ref) == {0, 1}
|
||||
for c in ref:
|
||||
assert np.array_equal(np.asarray(got[c]), np.asarray(ref[c]))
|
||||
|
||||
|
||||
def test_support_weighted_delegates_exactly():
|
||||
contributions, _ = _fixture()
|
||||
for beta in (0.0, 0.25, 0.5, 0.75, 1.0):
|
||||
got = V.aggregate_variant(contributions, "support_weighted", beta=beta)
|
||||
ref = aggregate_class_prototypes(contributions, "support_weighted", beta=beta)
|
||||
for c in ref:
|
||||
assert np.array_equal(np.asarray(got[c]), np.asarray(ref[c]))
|
||||
|
||||
|
||||
def test_beta0_is_equal_mean():
|
||||
contributions, _ = _fixture()
|
||||
base = V.aggregate_variant(contributions, "original_protean")
|
||||
for mode in ("support_weighted", "v_beta"):
|
||||
got = V.aggregate_variant(contributions, mode, beta=0.0)
|
||||
for c in base:
|
||||
np.testing.assert_allclose(got[c], base[c], rtol=0, atol=1e-12)
|
||||
# and v_beta beta1 == support_weighted beta1
|
||||
a = V.aggregate_variant(contributions, "v_beta", beta=1.0)
|
||||
b = V.aggregate_variant(contributions, "support_weighted", beta=1.0)
|
||||
for c in a:
|
||||
np.testing.assert_allclose(a[c], b[c], rtol=0, atol=1e-12)
|
||||
|
||||
|
||||
def test_single_contributor_invariance():
|
||||
proto = np.arange(6, dtype=float)
|
||||
contributions = {0: [(proto, 17)]}
|
||||
for mode in V.VARIANT_MODES:
|
||||
for beta in (0.0, 0.5, 1.0):
|
||||
got = V.aggregate_variant(contributions, mode, beta=beta)
|
||||
np.testing.assert_allclose(got[0], proto, rtol=0, atol=0)
|
||||
|
||||
|
||||
def test_equal_support_invariance():
|
||||
rng = np.random.default_rng(11)
|
||||
contributions = {0: [(rng.normal(size=5), 100) for _ in range(4)]}
|
||||
means = [np.asarray(V.aggregate_variant(contributions, "support_weighted", beta=b)[0])
|
||||
for b in (0.0, 0.25, 0.5, 0.75, 1.0)]
|
||||
for m in means[1:]:
|
||||
np.testing.assert_allclose(m, means[0], rtol=0, atol=1e-12)
|
||||
|
||||
|
||||
def test_missing_class_never_fabricated():
|
||||
contributions, _ = _fixture()
|
||||
for mode in V.ALL_MODES:
|
||||
kwargs = {"beta": 0.0} if mode != "original_protean" else {}
|
||||
got = V.aggregate_variant(contributions, mode, **kwargs)
|
||||
assert 2 not in got
|
||||
for vec in got.values():
|
||||
assert np.all(np.isfinite(vec))
|
||||
assert np.any(np.asarray(vec) != 0.0)
|
||||
|
||||
|
||||
def test_shrink_endpoints():
|
||||
contributions, _ = _fixture()
|
||||
equal = V.aggregate_variant(contributions, "original_protean")
|
||||
sw = V.aggregate_variant(contributions, "support_weighted", beta=1.0)
|
||||
s0 = V.aggregate_variant(contributions, "v_shrink", beta=1.0, shrink_lambda=0.0)
|
||||
s1 = V.aggregate_variant(contributions, "v_shrink", beta=1.0, shrink_lambda=1.0)
|
||||
for c in equal:
|
||||
np.testing.assert_allclose(s0[c], equal[c], atol=1e-12)
|
||||
np.testing.assert_allclose(s1[c], sw[c], atol=1e-12)
|
||||
|
||||
|
||||
def test_cap_extremes():
|
||||
contributions, _ = _fixture()
|
||||
sw = V.aggregate_variant(contributions, "support_weighted", beta=1.0)
|
||||
big = V.aggregate_variant(contributions, "v_cap", beta=1.0, cap_factor=1e9)
|
||||
for c in sw:
|
||||
np.testing.assert_allclose(big[c], sw[c], atol=1e-9)
|
||||
small = V.aggregate_variant(contributions, "v_cap", beta=1.0, cap_factor=1.0)
|
||||
for c in sw:
|
||||
assert np.all(np.isfinite(small[c]))
|
||||
|
||||
|
||||
def test_minsup_participant_change():
|
||||
rng = np.random.default_rng(3)
|
||||
p_small, p_big = rng.normal(size=4), rng.normal(size=4)
|
||||
contributions = {0: [(p_small, 1), (p_big, 100)]}
|
||||
got = V.aggregate_variant(contributions, "v_minsup", beta=0.0, min_support=10)
|
||||
np.testing.assert_allclose(got[0], p_big, atol=0)
|
||||
# fallback when every contributor is below the threshold
|
||||
contributions = {0: [(p_small, 1), (p_big, 2)]}
|
||||
got = V.aggregate_variant(contributions, "v_minsup", beta=0.0, min_support=10)
|
||||
np.testing.assert_allclose(got[0], _mean([p_small, p_big]), atol=1e-12)
|
||||
|
||||
|
||||
def test_logweight_positive_and_deterministic():
|
||||
contributions, _ = _fixture()
|
||||
a = V.aggregate_variant(contributions, "v_logweight", beta=0.0)
|
||||
b = V.aggregate_variant(contributions, "v_logweight", beta=0.0)
|
||||
for c in a:
|
||||
assert np.array_equal(np.asarray(a[c]), np.asarray(b[c]))
|
||||
assert np.all(np.isfinite(a[c]))
|
||||
|
||||
|
||||
def test_invalid_parameters():
|
||||
contributions, _ = _fixture()
|
||||
with pytest.raises(ValueError):
|
||||
V.aggregate_variant(contributions, "v_beta", beta=2.5)
|
||||
with pytest.raises(ValueError):
|
||||
V.aggregate_variant(contributions, "v_shrink", beta=0.5, shrink_lambda=1.5)
|
||||
with pytest.raises(ValueError):
|
||||
V.aggregate_variant(contributions, "v_cap", beta=0.5, cap_factor=0.5)
|
||||
with pytest.raises(ValueError):
|
||||
V.aggregate_variant(contributions, "not_a_mode", beta=0.5)
|
||||
with pytest.raises(ValueError):
|
||||
V.aggregate_variant(contributions, "v_beta", beta=None)
|
||||
@@ -0,0 +1,454 @@
|
||||
# Audit Ketangguhan (Robustness) dan Persiapan Penguji Tesis PROTEAN
|
||||
|
||||
Dokumen ini merupakan audit berbasis bukti dan bahan persiapan sidang untuk penelitian
|
||||
**agregasi prototype terbobot pada PROTEAN**. Seluruh angka diambil dari artefak eksperimen yang
|
||||
telah selesai; tidak ada pelatihan ulang, tidak ada perubahan pada algoritma, model, loss,
|
||||
optimizer, dataset, partisi, maupun hasil eksperimen. Skrip pendukung berada di
|
||||
`kisikisithesis/robustness_checks.py` dan bersifat deterministik serta hanya-baca.
|
||||
|
||||
Status repositori saat audit: branch `main`, HEAD `34bab45`, tidak ada perubahan pada berkas
|
||||
terlacak. Direktori `kisikisithesis/` seluruhnya baru.
|
||||
|
||||
---
|
||||
|
||||
## 1. Ringkasan Eksekutif
|
||||
|
||||
1. **Mekanisme yang diubah hanya agregasi prototype di sisi server.** Bobot client
|
||||
`w_ij(β) = N_ij^β / Σ_{k∈S_j} N_kj^β` dengan `β ∈ {0, 0.25, 0.50, 0.75, 1.00}`; model lokal,
|
||||
loss, optimizer, inferensi, dataset, dan manifest partisi tetap.
|
||||
2. **Sifat yang dijamin oleh rumus** (diverifikasi sintetis, `robustness_checks.py`):
|
||||
`β=0` = rata-rata aritmetik atas `S_j`; `β=1` = rata-rata terbobot dukungan; satu penyumbang
|
||||
invarian terhadap `β`; dukungan seragam invarian terhadap `β`; bobot selalu berjumlah 1;
|
||||
`N_ij=0` dan prototype hilang dikeluarkan dari `S_j`; `β` tak valid ditolak.
|
||||
3. **Efek langsung vs efek akhir-ke-akhir berbeda.** Displacement prototype `‖C̄_j(β)−C̄_j(0)‖`
|
||||
naik monoton terhadap `β` (X-IIoTID 1.305–3.422; 5G-NIDD 1.385–2.919 pada `β=1`), tetapi
|
||||
displacement besar **bukan** bukti deteksi membaik.
|
||||
4. **Hasil akhir-ke-akhir kecil dan bergantung kondisi.** Perbedaan rare-class macro-F1 uji:
|
||||
−0,0007 / +0,0230 / +0,0014 (X-IIoTID) dan −0,0010 / −0,0086 / +0,0168 (5G-NIDD). Hanya
|
||||
X-IIoTID α=0,50 yang arahnya konsisten pada ketiga seed.
|
||||
5. **Daya uji statistik tidak memadai.** Dengan 3 seed, p terkecil yang mungkin untuk uji tanda
|
||||
eksak dua sisi adalah **0,25** (diverifikasi); hanya X-IIoTID α=0,50 mencapainya. Maka tidak
|
||||
ada klaim signifikansi.
|
||||
6. **Pemilihan β rapuh secara relatif.** Margin terbaik vs terbaik kedua hanya **0,0024–0,0122**,
|
||||
dan kesepakatan seleksi pooled dengan seleksi per-seed paling banyak **2 dari 3**.
|
||||
7. **Asumsi reproduksi `S_j` material.** `|S_j| < M` pada **53 dari 162** sel kelas-kondisi.
|
||||
8. **Reproduksi vs paper belum dapat diverifikasi** karena `journal/main.tex` (dan Table IV paper)
|
||||
tidak ada di repositori ini.
|
||||
|
||||
Kalimat klaim yang aman: *"Di antara kandidat β yang diuji, pembobotan dukungan sampel kelas
|
||||
memberi perubahan rare-class macro-F1 yang kecil dan bergantung kondisi; hanya sebagian kondisi
|
||||
menunjukkan perbaikan yang konsisten antar-seed, dan tidak ada klaim signifikansi statistik."*
|
||||
|
||||
---
|
||||
|
||||
## 2. Inventaris Repositori dan Bukti
|
||||
|
||||
Sumber utama (semua sudah tersimpan, hanya-baca):
|
||||
|
||||
| Keperluan | Artefak |
|
||||
|---|---|
|
||||
| Protokol beku | `docs/research/EXPERIMENT_PROTOCOL.md`, `configs/experiments/experiment_protocol.yaml` |
|
||||
| Implementasi agregasi | `src/protean_research/aggregation/prototype_aggregation.py` |
|
||||
| Efek agregasi langsung | `src/protean_research/analysis/direct_prototype.py`, `scripts/analyze_prototype_effect.py` |
|
||||
| Snapshot prototype | `artifacts/analysis/*prototype_snapshot.json` (108 berkas; 18 sel × 6 konfigurasi) |
|
||||
| Partisi beku | `artifacts/partitions/*.json` (18 manifest) |
|
||||
| Perbandingan berpasangan | `artifacts/analysis/deepcmp__*.csv` |
|
||||
| Ringkasan enam kondisi | `artifacts/analysis/final__six_condition_master.csv` |
|
||||
| Kurva seleksi | `final__pooled_validation_curves.csv`, `final__selection_strength.csv` |
|
||||
| Sensitivitas β (tabel) | `final__prototype_displacement_by_beta.csv`, `..._by_class.csv` |
|
||||
| Heterogenitas terealisasi | `final__realized_heterogeneity.csv` |
|
||||
| Aturan `S_j` | `artifacts/analysis/sj_participant_rule_analysis.csv` |
|
||||
| Ekuivalensi β=0 | `*__multiseed__beta0_equivalence.csv` (5 kondisi; X-IIoTID α=0,50 tidak ada) |
|
||||
| Audit statistik | `docs/research/POSTHOC_STATISTICAL_AUDIT.md`, `artifacts/analysis/posthoc__*.csv` |
|
||||
| Metrik per-run | `results/<run>/test_global_metrics.json`, `test_per_class.csv`, `per_client.csv` |
|
||||
| Validasi per-seed | `artifacts/analysis/<ds>__alpha*__multiseed__validation_per_seed.csv` |
|
||||
| Baseline tereproduksi | `docs/baseline/BASELINE_VALIDATION.md`, `PROTEAN_BASELINE_INVESTIGATION.md` |
|
||||
|
||||
**Batas bukti yang harus dicatat:**
|
||||
- `journal/main.tex` / Table IV paper **tidak ada** → perbandingan metrik paper tidak dapat
|
||||
diverifikasi.
|
||||
- `xiiotid__alpha0.5__multiseed__beta0_equivalence.csv` **tidak ada**, dan satu run
|
||||
`xiiotid__alpha0.5__seed0__original_protean` kehilangan artefak validasi.
|
||||
- Hanya **3 seed** per kondisi.
|
||||
- Pemilihan β memakai **rata-rata per-client (validasi)**, sedangkan headline memakai
|
||||
**rare-class macro-F1 global (uji)**.
|
||||
|
||||
Analisis yang **dapat** dihitung dari artefak: seluruh perbandingan berpasangan, displacement
|
||||
langsung, stabilitas seleksi, audit `S_j`, ringkasan per-kelas/per-client.
|
||||
Analisis yang **memerlukan pelatihan baru**: menambah seed, dataset, arsitektur, atau kandidat β
|
||||
kontinu.
|
||||
|
||||
---
|
||||
|
||||
## 3. Penjelasan Matematis β dan Bobot Client (terverifikasi)
|
||||
|
||||
Diberikan himpunan peserta `S_j = { i : N_ij > 0 dan prototype lokal C_ij valid }`. Bobot
|
||||
ternormalisasi dan prototype global:
|
||||
|
||||
```
|
||||
w_ij(β) = N_ij^β / Σ_{k∈S_j} N_kj^β
|
||||
C̄_j(β) = Σ_{i∈S_j} w_ij(β) · C_ij
|
||||
```
|
||||
|
||||
**β = 0.** `N_ij^0 = 1` sehingga `w_ij = 1/|S_j|` dan `C̄_j(0)` adalah rata-rata aritmetik atas
|
||||
`S_j`. Ini adalah **kontrol setara**, bukan otomatis sama dengan baseline PROTEAN: kesetaraan hanya
|
||||
berlaku bila aturan peserta/penanganan kelas-tak-tersedia juga sama.
|
||||
|
||||
**β = 1.** `w_ij ∝ N_ij`. Karena setiap `C_ij` adalah rata-rata embedding kelas lokal, `C̄_j(1)`
|
||||
setara dengan rata-rata gabungan seluruh embedding kelas `j` yang disertakan bila seluruh asumsi
|
||||
terpenuhi.
|
||||
|
||||
**0 < β < 1.** Bobot tumbuh sub-linear terhadap dukungan: client berdukungan besar lebih
|
||||
berpengaruh, tetapi tidak sepenuhnya proporsional.
|
||||
|
||||
**Mengapa β besar tidak menjamin deteksi lebih baik.** Agregasi hanya menghasilkan posisi
|
||||
`C̄_j(β)`; inferensi memilih prototype terdekat (jarak L2). Meningkatnya bobot client berdukungan
|
||||
besar dapat menggeser `C̄_j` ke arah cluster padat tetapi **kurang mewakili** variasi serangan
|
||||
langka, sehingga menurunkan recall kelas langka. Jadi peningkatan `β` mengubah geometri prototype
|
||||
secara deterministik, tetapi hubungannya dengan kinerja deteksi bersifat empiris dan bergantung
|
||||
data.
|
||||
|
||||
**N_ij = 0.** Client tidak menyumbang prototype untuk kelas tersebut dan tidak masuk `S_j`;
|
||||
implementasi tidak pernah membuat vektor nol (`aggregate_class_prototypes`, baris penyaring
|
||||
`support <= 0 atau proto is None`).
|
||||
|
||||
**Mengapa penyebut dan aturan peserta penting.** Bila Eq. (2) paper (`1/M` atas semua client)
|
||||
diterapkan harfiah dengan mengisi prototype hilang sebagai nol, hasilnya berbeda dari `1/|S_j|`.
|
||||
Pada **53/162** sel kelas-kondisi, `|S_j| < M`, sehingga aturan ini material dan seluruh hasil
|
||||
bersifat kondisional.
|
||||
|
||||
**Sifat yang dijamin rumus** (diverifikasi): normalisasi (Σw=1), endpoint β, invariansi satu
|
||||
penyumbang/dukungan seragam, pengecualian `N_ij=0`, penolakan β tak valid.
|
||||
**Sifat yang bergantung data/implementasi**: besar displacement per kelas, client mana yang
|
||||
dominan, dan apakah deteksi membaik.
|
||||
|
||||
---
|
||||
|
||||
## 4. Temuan Sensitivitas Parameter yang Ada (efek agregasi langsung)
|
||||
|
||||
Dihitung ulang dari snapshot round-0 yang tersimpan oleh `kisikisithesis/robustness_checks.py`
|
||||
(tanpa pelatihan, snapshot tidak diubah).
|
||||
|
||||
**Tabel kondisi (mean displacement `‖C̄_j(1)−C̄_j(0)‖`, dari
|
||||
`final__prototype_displacement_by_beta.csv`):**
|
||||
|
||||
| Dataset | α=0.25 | α=0.50 | α=0.75 |
|
||||
|---|---|---|---|
|
||||
| X-IIoTID | 3.422 (β=0.25: 1.476; β=0.50: 2.403; β=0.75: 3.003) | 2.099 | 1.305 |
|
||||
| 5G-NIDD | 2.919 (1.295 / 2.055 / 2.559) | 2.340 | 1.385 |
|
||||
|
||||
Displacement naik **monoton** terhadap β di setiap kondisi; makin kecil α (makin timpang),
|
||||
makin besar displacement.
|
||||
|
||||
**Contoh sensitivitas per kelas (5G-NIDD α=0.25 seed 0, snapshot β=0):**
|
||||
|
||||
| Kelas | \|S_j\| | N_min | N_max | disp@0.5 | disp@1.0 | bobot client terbesar @β=1 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| HTTPFlood | 9 | 1 | 48.469 | 3.895 | 4.727 | 0.492 |
|
||||
| TCPConnectScan | 9 | 2 | 10.870 | 4.040 | 6.173 | 0.774 |
|
||||
| SlowrateDoS | 9 | 1 | 16.517 | 3.606 | 4.216 | 0.323 |
|
||||
| SYNFlood | 7 | 144 | 4.762 | 1.151 | 2.726 | 0.700 |
|
||||
| Benign | 10 | 1 | 185.504 | 2.335 | 3.229 | 0.555 |
|
||||
|
||||
Pada snapshot ini, mean disp@1.0 untuk kelas `|S_j|<M` (6 kelas) = **3.619** vs `|S_j|=M`
|
||||
(3 kelas) = **3.537**. Pada X-IIoTID α=0.25 seed 0: **3.620** vs **2.726** (kelas dengan
|
||||
peserta tidak lengkap bergeser lebih jauh). Ini **deskriptif**, bukan kausal.
|
||||
|
||||
**Kasus prototype berubah tanpa bukti perbaikan deteksi (penting).** Contoh `TCPConnectScan`
|
||||
bergeser 6.173 pada β=1, tetapi perubahan F1 uji kelas ini kecil dan bergantung kondisi. Jadi
|
||||
displacement ≠ kinerja deteksi; ini dibahas juga di §5 dan §8.
|
||||
|
||||
**Catatan utility langsung.** `prototype_effect_rows` dan `client_weight_rows`
|
||||
(`src/protean_research/analysis/direct_prototype.py`) menghitung displacement dan bobot dari
|
||||
snapshot yang sama; tidak memodifikasi snapshot dan tidak memicu pelatihan.
|
||||
|
||||
---
|
||||
|
||||
## 5. Temuan Robustness End-to-End yang Ada
|
||||
|
||||
Berbasis audit post-hoc (`posthoc__*.csv`); angka terverifikasi.
|
||||
|
||||
**Perbedaan berpasangan rare-class macro-F1 uji (proposed − original), per seed:**
|
||||
|
||||
| Dataset | α | β* | Δ s0 | Δ s1 | Δ s2 | mean | std berpasangan | std base | std proposed | +/−/0 | arah sama |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| X-IIoTID | 0.25 | 0.00 | +0.0016 | −0.0020 | −0.0016 | −0.0007 | 0.0019 | 0.0472 | 0.0476 | 1/2/0 | tidak |
|
||||
| X-IIoTID | 0.50 | 0.75 | +0.0266 | +0.0163 | +0.0261 | **+0.0230** | 0.0058 | 0.0287 | 0.0267 | 3/0/0 | **ya** |
|
||||
| X-IIoTID | 0.75 | 0.50 | −0.0097 | +0.0101 | +0.0036 | +0.0014 | 0.0101 | 0.0778 | 0.0855 | 2/1/0 | tidak |
|
||||
| 5G-NIDD | 0.25 | 0.00 | −0.0050 | −0.0010 | +0.0029 | −0.0010 | 0.0039 | 0.0254 | 0.0242 | 1/2/0 | tidak |
|
||||
| 5G-NIDD | 0.50 | 1.00 | +0.0090 | −0.0811 | +0.0464 | −0.0086 | 0.0655 | 0.0371 | 0.0285 | 2/1/0 | tidak |
|
||||
| 5G-NIDD | 0.75 | 0.50 | −0.0011 | +0.0450 | +0.0067 | +0.0168 | 0.0247 | 0.0231 | 0.0145 | 2/1/0 | tidak |
|
||||
|
||||
- **Recall kelas langka turun pada 5/6 kondisi** (dan pada **semua 4** kondisi β>0): perolehan F1
|
||||
cenderung berasal dari presisi.
|
||||
- **Uji eksak (n=3):** sign-flip p = 0.75 / **0.25** / 0.75 / 0.75 / 1.00 / 0.50; Wilcoxon p =
|
||||
1.00 / 0.50 / 1.00 / 1.00 / 1.00 / 1.00. p terkecil yang mungkin = **0.25**.
|
||||
- **Confusion matrix** (5G-NIDD α=0.75 seed0): error dominan `Benign → UDPFlood` nyaris tetap
|
||||
(56.899 → 57.054; **+155**, bukan perbaikan); error `HTTPFlood → SlowrateDoS` turun 547;
|
||||
`Benign → TCPConnectScan` turun 520; `SlowrateDoS → HTTPFlood` naik 229.
|
||||
- **Per kelas** (mean ΔF1 atas semua 9 observasi): Tampering +0.052, Reconnaissance +0.030,
|
||||
ICMPFlood +0.027; SYNFlood −0.019, C&C −0.018. Konsistensi antar-seed tidak merata.
|
||||
- **Per client:** redistribusi — sebagian client naik, sebagian turun; pada α=0.25 beta=0 semua
|
||||
client "tidak berubah". Analisis dukungan rendah bersifat deskriptif (Pearson Δ vs fraksi
|
||||
dukungan ≈ −0,09; n=120).
|
||||
|
||||
**Diagnostik seleksi:** margin 0,0024–0,0122; kesepakatan pooled vs per-seed ≤2/3; pooled
|
||||
per-seed: X 0.75/0.50/0.00; 0.50/1.00/0.75; 0.50/0.50/0.00 dan 5G 0.25/0.00/0.00; 1.00/0.00/1.00;
|
||||
0.50/1.00/1.00.
|
||||
|
||||
**Eksperimen yang dikecualikan:** kondisi X-IIoTID α=0,50 tidak memiliki artefak ekuivalensi β=0
|
||||
dan kehilangan artefak validasi untuk original seed 0; analisis langsung memakai sel yang lengkap.
|
||||
|
||||
---
|
||||
|
||||
## 6. Pertanyaan Penguji dan Jawaban (≥20)
|
||||
|
||||
Format: **Jawaban lisan (ID)** · *Alasan teknis* · *Bukti* · *Tindak lanjut* · *Peringatan*.
|
||||
|
||||
**Q1. Apa yang berubah jika β = 0, 0,5, atau 1?**
|
||||
Jawab: "β=0 berarti rata-rata sederhana atas client penyumbang; β=1 berarti kontribusi
|
||||
proporsional terhadap jumlah sampel kelas; β=0,5 adalah kompromi sub-linear." *Alasan:* rumus di
|
||||
§3. *Bukti:* `test_beta0_is_equal_arithmetic_mean_over_s_j`, `test_beta1_is_support_weighted_mean`;
|
||||
`robustness_checks.py` (β=0 → [1.333,1.667]; β=1 → [1.857,2.286]; β=0,5 → [1.586,2.000]).
|
||||
*Tindak lanjut:* "Apakah β=0 identik dengan PROTEAN asli?" → lihat Q13. *Peringatan:* perubahan
|
||||
prototype tidak otomatis mengubah kinerja deteksi.
|
||||
|
||||
**Q2. Mengapa memilih himpunan kandidat β ini?**
|
||||
Jawab: "Lima kandidat diskret menutupi dua ujung dan tiga titik antara agar eksperimen tetap
|
||||
terkendali dan terjangkau, sesuai spesifikasi riset." *Alasan:* protokol membekukan
|
||||
`{0,0.25,0.5,0.75,1.0}`. *Bukti:* `EXPERIMENT_PROTOCOL.md`, `test_beta_candidates_are_the_frozen_protocol_values`.
|
||||
*Tindak lanjut:* "Mengapa tidak β kontinu?" *Peringatan:* belum ada analisis β kontinu.
|
||||
|
||||
**Q3. Apa yang terjadi bila partisi makin/tidak makin non-IID?**
|
||||
Jawab: "Makin kecil α, dukungan kelas makin timpang dan displacement prototype makin besar;
|
||||
sebaliknya pada α besar hampir seragam." *Alasan & bukti:* `final__realized_heterogeneity.csv`,
|
||||
`final__prototype_displacement_by_beta.csv` (displacement β=1 turun saat α naik). *Tindak lanjut:*
|
||||
"Apakah α menyebabkannya?" *Peringatan:* hanya asosiasi deskriptif; α adalah knob, bukan
|
||||
heterogenitas terealisasi.
|
||||
|
||||
**Q4. Bagaimana bila kelas langka absen di sebagian besar client?**
|
||||
Jawab: "Kelas itu hanya diagregasi dari client yang memilikinya (`S_j`); bila tidak ada penyumbang,
|
||||
kelas dihilangkan dari hasil agregasi." *Bukti:* `test_class_with_only_missing_contributors_is_omitted`,
|
||||
`aggregate_class_prototypes`. *Tindak lanjut:* "Bagaimana pengaruhnya pada evaluasi rare-class?"
|
||||
*Peringatan:* kelangkaan ekstrem membatasi daya metrik.
|
||||
|
||||
**Q5. Apa yang terjadi ketika N_ij = 0?**
|
||||
Jawab: "Client tidak masuk `S_j` dan tidak ada vektor nol yang dibuat." *Bukti:*
|
||||
`aggregate_class_prototypes` (penyaring `support <= 0`), `test_missing_class_is_excluded_from_s_j`.
|
||||
*Tindak lanjut:* Q14.
|
||||
|
||||
**Q6. Bagaimana bila satu client jauh lebih banyak sampelnya?**
|
||||
Jawab: "Pada β tinggi bobotnya mendominasi; pada β=0 semua setara." *Bukti:* synthetic dominance
|
||||
[1,1000] → bobot 0,999 bagian; snapshot TCPConnectScan bobot client terbesar ≈0,774 pada β=1.
|
||||
*Tindak lanjut:* "Apakah ini selalu baik?" *Peringatan:* dominasi dapat menekan variasi kelas
|
||||
langka.
|
||||
|
||||
**Q7. Mengapa dukungan spesifik kelas, bukan total sampel client?**
|
||||
Jawab: "Bobot diterapkan per kelas, jadi relevan jumlah sampel kelas tersebut; total client tidak
|
||||
mewakili dukungan kelas tertentu." *Alasan:* `N_ij` didefinisikan per kelas. *Bukti:*
|
||||
`prototype_aggregation.py` menggunakan `N_ij` per kelas. *Tindak lanjut:* "Bisakah total sampel
|
||||
dipakai?" → mungkin sebagai pembanding, tetapi berbeda semantik.
|
||||
|
||||
**Q8. Apakah prototype yang berubah pasti memperbaiki klasifikasi?**
|
||||
Jawab: "Tidak." *Bukti:* displacement monoton naik terhadap β, sedangkan respons deteksi
|
||||
non-monoton (`final__prototype_displacement_by_beta.csv` vs `final__pooled_validation_curves.csv`).
|
||||
*Tindak lanjut:* Q9. *Peringatan:* jangan menyamakan displacement dengan kinerja.
|
||||
|
||||
**Q9. Mengapa macro-F1 bisa naik tetapi recall/presisi turun?**
|
||||
Jawab: "F1 adalah rata-rata harmonik; pergeseran prototype dapat mengubah trade-off
|
||||
presisi–recall." *Bukti:* rare-class recall turun di 5/6 kondisi; contoh Tampering (ΔF1 +0,144,
|
||||
Δpresisi +0,212, Δrecall −0,009 di X-IIoTID α=0,50). *Tindak lanjut:* "Apakah itu bermanfaat?"
|
||||
|
||||
**Q10. Bagaimana bila β terpilih tidak terbaik di uji?**
|
||||
Jawab: "Mungkin saja; seleksi memakai validasi, uji tidak boleh dipakai memilih β." *Bukti:*
|
||||
`test_used_for_selection = false`; `final__selection_strength.csv`. *Tindak lanjut:* Q12.
|
||||
|
||||
**Q11. Mengapa hanya tiga seed, dan apa yang tidak dapat disimpulkan?**
|
||||
Jawab: "Tiga seed sesuai protokol proyek; belum cukup untuk klaim signifikansi." *Bukti:* p
|
||||
terkecil yang mungkin = 0,25 (`posthoc__paired_test_results.csv`). *Tindak lanjut:* Q16.
|
||||
*Peringatan:* ketidaksignifikanan ≠ tidak ada efek.
|
||||
|
||||
**Q12. Apa implikasi margin seleksi kecil?**
|
||||
Jawab: "Seleksi rapuh; β terpilih adalah 'terbaik di antara kandidat yang diuji', bukan optimal."
|
||||
*Bukti:* margin 0,0024–0,0122; kesepakatan ≤2/3. *Tindak lanjut:* "Perlu seed tambahan?"
|
||||
|
||||
**Q13. Mengapa β=0 dianggap setara dengan agregasi bobot seragam asli, dan bagaimana diverifikasi?**
|
||||
Jawab: "β=0 secara matematis = rata-rata seragam atas `S_j`; kesetaraan dengan baseline asli hanya
|
||||
bila aturan peserta sama." *Bukti:* `test_beta0_matches_original_protean_on_identical_s_j`;
|
||||
`*__multiseed__beta0_equivalence.csv` (kelas B; `aggregation_max_abs_diff` ≈ 2e−16; snapshot
|
||||
round-0 byte-identik). *Tindak lanjut:* "Mengapa tidak bitwise identik?" *Peringatan:* bukan bukti
|
||||
reproduksi PROTEAN asli; masih ada divergensi floating-point end-to-end. X-IIoTID α=0,50 tidak
|
||||
punya artefak ekuivalensi ini (celah).
|
||||
|
||||
**Q14. Bagaimana perilaku bila |S_j| < jumlah client?**
|
||||
Jawab: "Hanya client di `S_j` yang diagregasi; penyebut memakai jumlah bobot kontributor."
|
||||
*Bukti:* `sj_participant_rule_analysis.csv` (53/162 sel), kode `aggregate_class_prototypes`.
|
||||
*Tindak lanjut:* "Apa alternatifnya?" *Peringatan:* aturan ini asumsi reproduksi.
|
||||
|
||||
**Q15. Bisakah pembobotan dukungan memperburuk kinerja? Mekanisme masuk akal?**
|
||||
Jawab: "Bisa, secara prinsip." *Alasan:* pada β tinggi, client berdukungan besar mendominasi;
|
||||
jika variasi kelas langka hanya ada di client berdukungan kecil, prototype global bergeser menjauh
|
||||
dari variasi itu → recall turun. *Bukti:* hal ini teramati pada **5G-NIDD α=0,50** (Δ = −0,0086)
|
||||
dan pada α=0,25 (β=1 paling merugikan di tingkat client, dari sintesis). *Peringatan:* contoh lain
|
||||
bersifat mekanisme hipotetis, bukan hasil teramati.
|
||||
|
||||
**Q16. Eksperimen tambahan apa yang paling langsung menguji reprodusibilitas efek?**
|
||||
Jawab: "Menambah seed pada kondisi terkuat (X-IIoTID α=0,50) dan kondisi terlemah (5G-NIDD α=0,50),
|
||||
lalu seleksi dan evaluasi berpasangan; idealnya juga beberapa arsitektur." *Alasan:* daya uji
|
||||
bergantung jumlah seed. *Bukti:* §5. *Tindak lanjut:* Q21.
|
||||
|
||||
**Q17. Asumsi apa yang berbeda dari paper PROTEAN?**
|
||||
Jawab: "Penanganan kelas tak tersedia (`S_j`), split 70/10/20 (paper 80/20), nilai λ tanpa rujukan,
|
||||
seed tak diberi paper, dan preprocessing yang tidak dispesifikasikan." *Bukti:*
|
||||
`PROTEAN_BASELINE_INVESTIGATION.md`, `EXPERIMENT_PROTOCOL.md`. *Peringatan:* perbedaan reproduksi,
|
||||
bukan otomatis bug.
|
||||
|
||||
**Q18. Apa implikasi privasi karena server menerima N_ij?**
|
||||
Jawab: "Server menerima hitungan dukungan per kelas selain prototype; ini memperluas informasi yang
|
||||
diungkap dibanding hanya prototype." *Alasan & bukti:* `client.py` menghasilkan `supports`;
|
||||
`server.py` meneruskan `client_supports` ke agregasi. *Peringatan:* **belum ada analisis
|
||||
threat-model/privasi**, jadi tidak boleh diklaim sebagai kerentanan; ini hanya deskripsi aliran data.
|
||||
|
||||
**Q19. Parameter mana yang tetap, mana yang disetel, mana bagian metode usulan?**
|
||||
Jawab: "Tetap: model, loss, optimizer, inferensi, dataset, partisi, arsitektur. Disetel: β.
|
||||
Bagian metode usulan: bobot `N_ij^β` pada agregasi prototype server." *Bukti:* §3,
|
||||
`prototype_aggregation.py`, protokol.
|
||||
|
||||
**Q20. Apa yang akan menggugurkan klaim empiris utama?**
|
||||
Jawab: "Bila pada seed tambahan perbaikan X-IIoTID α=0,50 tidak muncul, atau bila β terpilih tidak
|
||||
stabil, maka klaim 'perbaikan bergantung kondisi' harus diperlemah; klaim keunggulan universal
|
||||
sudah tidak diajukan." *Bukti:* §5. *Peringatan:* tanpa seed tambahan, ini belum diuji.
|
||||
|
||||
**Q21. Mengapa tidak menjalankan β kontinu?**
|
||||
Jawab: "Di luar lingkup dan biaya; grid diskret sudah dibekukan." *Bukti:* protokol. *Tindak
|
||||
lanjut:* sebagai pekerjaan lanjutan.
|
||||
|
||||
**Q22. Apa arti 'dukungan sampel' dan mengapa bukan ukuran kualitas?**
|
||||
Jawab: "`N_ij` adalah jumlah sampel training kelas j pada client i; bukan skor kualitas prototype."
|
||||
*Bukti:* `AGENTS.md` §9/§10, `prototype_aggregation.py`.
|
||||
|
||||
*(22 pertanyaan; mencakup seluruh daftar yang diminta.)*
|
||||
|
||||
---
|
||||
|
||||
## 7. Rencana Demonstrasi Perubahan Parameter Terkendali
|
||||
|
||||
Tidak dieksekusi otomatis oleh dokumen ini; `robustness_checks.py` telah menjalankan versi
|
||||
read-only untuk sebagian skenario. Semua demo memakai input sintetis kecil atau snapshot tersimpan.
|
||||
|
||||
| # | Skenario | Input terkendali | Hasil yang diharapkan (rumus) | Implementasi / tes yang ada | Perlu tes baru? | Penjelasan lisan |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1 | Endpoint β | `p=[[1,0],[0,2],[3,3]]`, `N=[5,10,20]` | β=0 → rata-rata; β=1 → terbobot | `test_beta0_...`, `test_beta1_...` | tidak | "Dua ujung rumus terbukti langsung." |
|
||||
| 2 | Normalisasi bobot | support apa pun > 0 | Σw = 1 | `test_normalized_weights_sum_to_one` | tidak | "Bobot selalu terdefinisi." |
|
||||
| 3 | Client dukungan nol | `N=[5,0,7]` | client 0 di luar `S_j` | `test_missing_class_is_excluded_from_s_j` | tidak | "Tanpa fabrikasi prototype." |
|
||||
| 4 | Dukungan seragam | `N=[4,4,4]` | invarian β | `test_equal_support_is_invariant_to_beta` | tidak | "Tanpa ketimpangan, β tak berpengaruh." |
|
||||
| 5 | Sangat timpang | `N=[1,1000]` | bobot ≈ [0,001; 0,999] | `robustness_checks.py` (dominance) | disarankan (unit test formal) | "Dominasi client besar." |
|
||||
| 6 | Ekuivalen β=0 | `S_j` identik | sama dengan rata-rata seragam | `test_beta0_matches_original_protean_on_identical_s_j`; `beta0_equivalence.csv` | tidak | "Kontrol, bukan asli." |
|
||||
| 7 | Stabilitas numerik / β tak valid | β ∈ {−0.1,1.1,None,"x",∞} | ValueError | `test_invalid_beta_is_rejected`, `test_output_is_finite_...` | tidak | "Validasi ketat." |
|
||||
| 8 | Sensitivitas satu client dominan terhadap prototype | snapshot nyata + client dominan | pergeseran prototype | `client_weight_rows`, `prototype_effect_rows` | tidak | "Pergeseran terukur, bukan kinerja." |
|
||||
|
||||
---
|
||||
|
||||
## 8. Audit Integritas Riset dan Batasan
|
||||
|
||||
**Klaim yang didukung eksperimen.** Desain berpasangan tervalidasi (manifest/split/seed sama);
|
||||
perbedaan rare-F1 uji kecil dan bergantung kondisi; hanya X-IIoTID α=0,50 konsisten positif;
|
||||
recall kelas langka cenderung turun; seleksi β rapuh; `S_j` material (53/162).
|
||||
|
||||
**Klaim yang hanya deskriptif.** Asosiasi timpang–displacement; redistribusi manfaat antar-client;
|
||||
dukungan rendah tidak dirugikan (asosiasi lemah, tanpa kausalitas).
|
||||
|
||||
**Asumsi reproduksi.** `S_j` dan penanganan kelas tak tersedia; split 70/10/20; λ=1,0; preprocessing;
|
||||
seed proyek; inisialisasi prototype round-0.
|
||||
|
||||
**Klaim yang harus dilemahkan/dihapus.** Superioritas/signifikansi; β optimal universal; bahwa
|
||||
displacement = deteksi lebih baik; keunggulan umum lintas dataset.
|
||||
|
||||
**Eksperimen tambahan yang memperkuat.** Penambahan seed (terutama X-IIoTID α=0,50 dan 5G α=0,50);
|
||||
dataset ketiga; arsitektur kedua; analisis β kontinu; analisis threat-model privasi `N_ij`.
|
||||
|
||||
**Analisis yang tidak layak dijalankan.** Uji inferensial dengan 3 seed (daya nihil); bootstrap
|
||||
interval dari 3 seed; menjadikan client sebagai replikasi independen (nested).
|
||||
|
||||
**Perhatian khusus:**
|
||||
- **Tiga seed** → p minimum 0,25.
|
||||
- **Celah reproduksi vs paper** → `journal/main.tex`/Table IV tidak ada; belum terverifikasi.
|
||||
- **`S_j`** → 53/162 sel; asumsi, bukan statistik.
|
||||
- **Metrik seleksi vs headline** → per-client mean (validasi) vs global (uji).
|
||||
- **Displacement vs deteksi** → dipisahkan.
|
||||
- **Privasi** → deskripsi aliran `N_ij`; belum ada threat-model.
|
||||
|
||||
---
|
||||
|
||||
## 9. Eksperimen Lanjutan Prioritas (dengan estimasi komputasi)
|
||||
|
||||
Estimasi berdasar runtime terukur (`artifacts/analysis/*__multiseed__runtime.csv`): 5G-NIDD
|
||||
≈ 62–65 menit/run, X-IIoTID ≈ 40–45 menit/run; 108 run ≈ 94,5 jam CPU (8 core).
|
||||
|
||||
| Prioritas | Eksperimen | Rasional | Estimasi biaya |
|
||||
|---|---|---|---|
|
||||
| 1 | Tambah seed (3→10) pada X-IIoTID α=0,50 dan 5G α=0,50 (kondisi terkuat & terlemah) | menguji reprodusibilitas efek terbesar & arah negatif | 2 kondisi × 7 seed × 6 config ≈ 84 run ≈ 70–75 jam |
|
||||
| 2 | Tambah seed penuh (3→10) semua 6 kondisi | daya uji dan stabilitas seleksi | ≈ 252 run ≈ 210–220 jam |
|
||||
| 3 | Dataset IDS ketiga | validitas eksternal | bergantung ukuran; ≈ 40–70 jam |
|
||||
| 4 | Arsitektur alternatif (mis. MLP/1D-CNN berbeda) | sensitivitas arsitektur | ≈ 90–200 jam |
|
||||
| 5 | Grid β kontinu (mis. 0.0–1.0 langkah 0.1) | resolusi kandidat | 6 kondisi × 3 seed × 6 β tambahan ≈ 108 run ≈ 90 jam |
|
||||
| 6 | Analisis threat-model privasi `N_ij` | klaim privasi | tanpa pelatihan (analistik) |
|
||||
|
||||
Tidak disarankan: uji signifikansi atau bootstrap dari 3 seed (informasi rendah, berisiko
|
||||
menyesatkan).
|
||||
|
||||
---
|
||||
|
||||
## 10. Cheat Sheet Pertahanan Lisan (satu halaman)
|
||||
|
||||
- **Mekanisme:** hanya agregasi prototype server; `w_ij(β)=N_ij^β/ΣN_kj^β`; `β∈{0,.25,.5,.75,1}`.
|
||||
- **β=0:** rata-rata seragam atas `S_j` (kontrol; setara baseline hanya bila aturan peserta sama).
|
||||
- **β=1:** terbobot dukungan; **β antara:** sub-linear.
|
||||
- **Hasil utama:** Δrare-F1 uji = X {−0,0007; +0,0230; +0,0014}, 5G {−0,0010; −0,0086; +0,0168}.
|
||||
- **Konsisten antar-seed:** hanya X-IIoTID α=0,50.
|
||||
- **Statistik:** n=3; p minimum 0,25; **tanpa klaim signifikansi**.
|
||||
- **Seleksi:** margin 0,0024–0,0122; rapuh; validasi-saja (`test_used_for_selection=false`).
|
||||
- **Direct vs end-to-end:** displacement naik monoton; deteksi non-monoton; dipisahkan.
|
||||
- **`S_j`:** 53/162 sel; asumsi reproduksi.
|
||||
- **Confusion dominan:** `Benign→UDPFlood` tetap (+155), bukan perbaikan.
|
||||
- **Jangan klaim:** superioritas universal, β optimal, displacement = deteksi lebih baik,
|
||||
signifikansi, kerentanan privasi tanpa threat-model.
|
||||
- **Celah:** paper Table IV tidak tersedia; X-IIoTID α=0,50 tanpa ekuivalensi β=0;
|
||||
artefak validasi seed0 original hilang.
|
||||
|
||||
---
|
||||
|
||||
## 11. Path Artefak dan Perintah Reproduksi
|
||||
|
||||
```bash
|
||||
# Pemeriksaan formula + efek agregasi langsung (read-only, tanpa pelatihan)
|
||||
.venv/bin/python kisikisithesis/robustness_checks.py
|
||||
|
||||
# Audit statistik post-hoc (read-only; hanya menulis posthoc__*.csv)
|
||||
.venv/bin/python scripts/posthoc_statistical_audit.py
|
||||
|
||||
# Analisis efek prototype langsung (read-only) - contoh
|
||||
.venv/bin/python scripts/analyze_prototype_effect.py \
|
||||
--snapshot artifacts/analysis/5gnidd__alpha0.25__seed0__support_weighted__beta0__prototype_snapshot.json \
|
||||
--class-names "Benign,HTTPFlood,ICMPFlood,SYNFlood,SYNScan,SlowrateDoS,TCPConnectScan,UDPFlood,UDPScan" \
|
||||
--output-dir /tmp/opencode/proto_effect # output di luar repo bila ingin menghindari file baru
|
||||
|
||||
# Uji unit agregasi & efek (read-only)
|
||||
.venv/bin/python -m pytest tests/test_support_weighted_aggregation.py tests/test_baseline_aggregation.py tests/test_prototype_effect.py
|
||||
```
|
||||
|
||||
Artefak kunci: `artifacts/analysis/deepcmp__*.csv`, `final__*.csv`,
|
||||
`posthoc__*.csv`, `sj_participant_rule_analysis.csv`, `*__multiseed__validation_per_seed.csv`,
|
||||
`*__multiseed__beta0_equivalence.csv`, `artifacts/partitions/*.json`.
|
||||
|
||||
---
|
||||
|
||||
## 12. Pertanyaan Tak Terjawab dan Bukti yang Hilang
|
||||
|
||||
1. **Metrik paper PROTEAN (Table IV)** tidak dapat diverifikasi: `journal/main.tex` tidak ada.
|
||||
2. **Ekuivalensi β=0 untuk X-IIoTID α=0,50** tidak tersedia (berkas tidak ada).
|
||||
3. **Artefak validasi seed 0 original X-IIoTID α=0,50** tidak lengkap.
|
||||
4. **Daya statistik** tidak memadai (3 seed); signifikansi tidak dapat diklaim.
|
||||
5. **Privasi `N_ij`** belum dianalisis dengan threat-model.
|
||||
6. **β kontinu** dan **generalisasi lintas dataset/arsitektur** belum diuji.
|
||||
7. **Ketidakpastian seleksi β** tidak dapat dipisahkan sepenuhnya dari variasi seed dengan n=3.
|
||||
@@ -0,0 +1,685 @@
|
||||
# Sweep summary report (server-side, read-only)
|
||||
|
||||
Generated: 2026-10-29 (UTC) by an agent session on the server that holds the
|
||||
sweep outputs. Scope: the state of `results/sweep/` and `results/sweep_repro/`
|
||||
as found on disk, plus the four analysis scripts now version-controlled under
|
||||
`scripts/sweep/`.
|
||||
|
||||
This report is descriptive. It does **not** claim statistical significance, does
|
||||
**not** select or recommend a beta, and does **not** compare the sweep with the
|
||||
paper. Where the analysis scripts emit a "selected" or "best" column, that
|
||||
column is reproduced verbatim as script output, not adopted here.
|
||||
|
||||
The raw data (`results/`) is git-ignored and is **not** committed. This report is
|
||||
also not committed.
|
||||
|
||||
---
|
||||
|
||||
## 1. Repository state at the start of the session
|
||||
|
||||
Commands and output:
|
||||
|
||||
```
|
||||
$ git status --short
|
||||
?? kisikisithesis/RESTORE_VERIFICATION_REPORT.md
|
||||
$ git branch --show-current
|
||||
chore/posthoc-audit-and-docs-refresh
|
||||
$ git log --oneline -5
|
||||
e66ecc4 docs: add 5G-NIDD repeat and multi-thread test (section 3.7)
|
||||
b40c928 docs: add repeat and multi-thread test (section 3.6) for the 1-thread sweep
|
||||
ad203eb docs: record 1-thread seed-0 sweep, noise checks and grid comparison
|
||||
91b0e37 chore: declare matplotlib and apply three behavior-preserving nits
|
||||
7831272 docs: refresh README and session handoff for current state
|
||||
```
|
||||
|
||||
- `scripts/sweep/` did not exist.
|
||||
- `git log --oneline --all -- scripts/sweep` returned nothing, so no commit
|
||||
adding it existed.
|
||||
- `git rev-parse main` and `git rev-parse origin/main` were both
|
||||
`34bab458651b80c617490a75b94b27fdcbbc19fb`.
|
||||
- The only pre-existing untracked file was
|
||||
`kisikisithesis/RESTORE_VERIFICATION_REPORT.md` (not created by this session,
|
||||
not touched, not committed).
|
||||
|
||||
`results/sweep/` and `results/sweep_repro/` exist on this server, matching the
|
||||
task statement that they are git-ignored (`.gitignore` line `results/`).
|
||||
|
||||
---
|
||||
|
||||
## 2. Queue outcome
|
||||
|
||||
Source: `results/sweep/queue.txt`, `results/sweep/summary.csv`,
|
||||
`results/sweep/runs/*/COMPLETE`, `results/sweep/logs/pool.log`.
|
||||
|
||||
- Queue rows: **30** (2 datasets x 3 alphas x 5 betas, seed 0).
|
||||
- Final `summary.csv` status counts: **30 completed, 0 failed** (exit code 0 in
|
||||
all 30 rows).
|
||||
- `COMPLETE` markers on disk: **30**.
|
||||
- `results/sweep/PHASE`: `done`.
|
||||
- Last `HEARTBEAT` (2026-10-29T00:02:03Z): `rows: completed=30 failed=0
|
||||
pending=0 total=30`, `training_processes: 0`.
|
||||
- The sweep is finished; no row is marked unfinished.
|
||||
|
||||
Failed attempts that were later replaced in `summary.csv` (the upsert keeps one
|
||||
row per config) are listed in section 4.
|
||||
|
||||
---
|
||||
|
||||
## 3. Completed runs: wall time and peak memory
|
||||
|
||||
Values are from `results/sweep/summary.csv`, which records `/usr/bin/time -v`
|
||||
wall seconds and maximum resident set size for the completed attempt. Peak RSS
|
||||
is converted from KiB to GiB (divide by 1,048,576). Rows are ordered by start
|
||||
time. `wall` is `h:mm:ss`.
|
||||
|
||||
| # | run | started (UTC) | ended (UTC) | wall | peak RSS (GiB) | status |
|
||||
|---:|---|---|---|---:|---:|---|
|
||||
| 1 | `5gnidd__alpha0.25__seed0__support_weighted__beta0` | 2026-10-26T07:31:29Z | 2026-10-26T12:55:25Z | 5:23:56 | 13.12 | completed |
|
||||
| 2 | `xiiotid__alpha0.25__seed0__support_weighted__beta0` | 2026-10-26T07:31:29Z | 2026-10-26T11:02:12Z | 3:30:42 | 8.38 | completed |
|
||||
| 3 | `xiiotid__alpha0.25__seed0__support_weighted__beta1` | 2026-10-26T07:31:29Z | 2026-10-26T11:06:03Z | 3:34:33 | 8.38 | completed |
|
||||
| 4 | `5gnidd__alpha0.25__seed0__support_weighted__beta1` | 2026-10-26T11:02:12Z | 2026-10-26T16:21:43Z | 5:19:30 | 13.11 | completed |
|
||||
| 5 | `xiiotid__alpha0.25__seed0__support_weighted__beta0.25` | 2026-10-27T01:13:26Z | 2026-10-27T04:25:41Z | 3:12:15 | 8.38 | completed |
|
||||
| 6 | `5gnidd__alpha0.25__seed0__support_weighted__beta0.25` | 2026-10-27T01:13:26Z | 2026-10-27T06:22:48Z | 5:09:21 | 13.12 | completed |
|
||||
| 7 | `xiiotid__alpha0.25__seed0__support_weighted__beta0.5` | 2026-10-27T01:13:26Z | 2026-10-27T04:25:12Z | 3:11:45 | 8.38 | completed |
|
||||
| 8 | `5gnidd__alpha0.25__seed0__support_weighted__beta0.5` | 2026-10-27T04:25:12Z | 2026-10-27T09:46:00Z | 5:20:47 | 13.11 | completed |
|
||||
| 9 | `xiiotid__alpha0.25__seed0__support_weighted__beta0.75` | 2026-10-27T04:25:41Z | 2026-10-27T07:55:55Z | 3:30:12 | 8.38 | completed |
|
||||
| 10 | `5gnidd__alpha0.25__seed0__support_weighted__beta0.75` | 2026-10-27T06:22:48Z | 2026-10-27T11:46:25Z | 5:23:36 | 13.11 | completed |
|
||||
| 11 | `xiiotid__alpha0.5__seed0__support_weighted__beta0` | 2026-10-27T07:55:55Z | 2026-10-27T11:20:41Z | 3:24:46 | 6.21 | completed |
|
||||
| 12 | `5gnidd__alpha0.5__seed0__support_weighted__beta0` | 2026-10-27T09:46:01Z | 2026-10-27T15:20:57Z | 5:34:55 | 10.28 | completed |
|
||||
| 13 | `xiiotid__alpha0.5__seed0__support_weighted__beta0.25` | 2026-10-27T11:20:42Z | 2026-10-27T14:55:30Z | 3:34:47 | 6.21 | completed |
|
||||
| 14 | `5gnidd__alpha0.5__seed0__support_weighted__beta0.25` | 2026-10-27T11:46:25Z | 2026-10-27T17:36:49Z | 5:50:23 | 10.29 | completed |
|
||||
| 15 | `xiiotid__alpha0.5__seed0__support_weighted__beta0.5` | 2026-10-27T14:55:31Z | 2026-10-27T18:44:43Z | 3:49:12 | 6.21 | completed |
|
||||
| 16 | `5gnidd__alpha0.5__seed0__support_weighted__beta0.5` | 2026-10-27T15:20:58Z | 2026-10-27T21:26:19Z | 6:05:21 | 10.29 | completed |
|
||||
| 17 | `xiiotid__alpha0.5__seed0__support_weighted__beta0.75` | 2026-10-27T17:36:49Z | 2026-10-27T21:35:28Z | 3:58:39 | 6.21 | completed |
|
||||
| 18 | `5gnidd__alpha0.5__seed0__support_weighted__beta0.75` | 2026-10-27T18:44:44Z | 2026-10-28T00:42:07Z | 5:57:23 | 10.29 | completed |
|
||||
| 19 | `xiiotid__alpha0.5__seed0__support_weighted__beta1` | 2026-10-27T21:26:20Z | 2026-10-28T01:05:49Z | 3:39:29 | 6.21 | completed |
|
||||
| 20 | `5gnidd__alpha0.5__seed0__support_weighted__beta1` | 2026-10-27T21:35:29Z | 2026-10-28T03:18:55Z | 5:43:26 | 10.31 | completed |
|
||||
| 21 | `xiiotid__alpha0.75__seed0__support_weighted__beta0` | 2026-10-28T00:42:07Z | 2026-10-28T04:23:48Z | 3:41:40 | 6.48 | completed |
|
||||
| 22 | `5gnidd__alpha0.75__seed0__support_weighted__beta0` | 2026-10-28T01:05:49Z | 2026-10-28T06:53:35Z | 5:47:44 | 8.61 | completed |
|
||||
| 23 | `xiiotid__alpha0.75__seed0__support_weighted__beta0.25` | 2026-10-28T03:18:56Z | 2026-10-28T07:05:59Z | 3:47:03 | 6.48 | completed |
|
||||
| 24 | `5gnidd__alpha0.75__seed0__support_weighted__beta0.25` | 2026-10-28T04:23:48Z | 2026-10-28T10:17:38Z | 5:53:48 | 8.61 | completed |
|
||||
| 25 | `xiiotid__alpha0.75__seed0__support_weighted__beta0.5` | 2026-10-28T06:53:35Z | 2026-10-28T10:40:37Z | 3:47:01 | 6.48 | completed |
|
||||
| 26 | `5gnidd__alpha0.75__seed0__support_weighted__beta0.5` | 2026-10-28T07:06:00Z | 2026-10-28T12:40:40Z | 5:34:40 | 8.61 | completed |
|
||||
| 27 | `xiiotid__alpha0.75__seed0__support_weighted__beta0.75` | 2026-10-28T10:17:38Z | 2026-10-28T13:32:01Z | 3:14:23 | 6.48 | completed |
|
||||
| 28 | `5gnidd__alpha0.75__seed0__support_weighted__beta0.75` | 2026-10-28T10:40:37Z | 2026-10-28T15:26:24Z | 4:45:46 | 8.61 | completed |
|
||||
| 29 | `xiiotid__alpha0.75__seed0__support_weighted__beta1` | 2026-10-28T12:40:40Z | 2026-10-28T15:37:02Z | 2:56:21 | 6.48 | completed |
|
||||
| 30 | `5gnidd__alpha0.75__seed0__support_weighted__beta1` | 2026-10-28T13:32:01Z | 2026-10-28T18:00:12Z | 4:28:10 | 8.61 | completed |
|
||||
|
||||
Totals over the 30 completed attempts:
|
||||
|
||||
- Sum of wall time: **486,694 s = 135.19 h** (not pool wall time; runs overlap).
|
||||
- X-IIoTID: n=15, wall 2:56:21-3:58:39, mean 3:31:31, max peak RSS 8.38 GiB.
|
||||
- 5G-NIDD: n=15, wall 4:28:10-6:05:21, mean 5:29:15, max peak RSS 13.12 GiB.
|
||||
- Global maximum peak RSS: **13.12 GiB** (`5gnidd alpha0.25 beta0` and
|
||||
`5gnidd alpha0.25 beta0.25`).
|
||||
- First pool start: 2026-10-26T02:10:14Z. Last completion:
|
||||
2026-10-28T18:00:12Z. Span: **2 days 15:49:58**.
|
||||
- From the final relaunch (2026-10-27T01:13:26Z) to the last completion:
|
||||
**1 day 16:46:46**.
|
||||
|
||||
### 3.1 Reproducibility runs in `results/sweep_repro/` (not queue rows)
|
||||
|
||||
These four runs are outside `results/sweep/summary.csv` and were launched with
|
||||
`results/sweep_repro/run_variant.sh` (1-thread = `thread1_launcher.py`, as in the
|
||||
sweep; 8-thread = plain `run_baseline.py`). They write `logs/start.epoch`,
|
||||
`logs/end.epoch`, `logs/exit_code` and `/usr/bin/time -v` output instead of a
|
||||
`COMPLETE` marker. All four exited 0 with empty `stderr.log`.
|
||||
|
||||
| config | variant dir | start (UTC) | end (UTC) | wall | peak RSS (GiB) | exit |
|
||||
|---|---|---:|---:|---:|---:|---:|
|
||||
| xiiotid alpha0.25 seed0 beta0 | `a_1thread_repeat` | 2026-10-29T00:40:42Z | 2026-10-29T03:22:26Z | 2:41:44 | 8.38 | 0 |
|
||||
| xiiotid alpha0.25 seed0 beta0 | `b_8thread` | 2026-10-29T00:40:42Z | 2026-10-29T01:56:28Z | 1:15:46 | 8.39 | 0 |
|
||||
| 5gnidd alpha0.5 seed0 beta0.75 | `5gnidd_a0.5_b0.75/a_1thread_repeat` | 2026-10-29T11:57:21Z | 2026-10-29T16:36:33Z | 4:39:11 | 10.29 | 0 |
|
||||
| 5gnidd alpha0.5 seed0 beta0.75 | `5gnidd_a0.5_b0.75/b_8thread` | 2026-10-29T11:57:21Z | 2026-10-29T14:39:23Z | 2:42:01 | 10.43 | 0 |
|
||||
|
||||
Peak RSS converted from `/usr/bin/time -v` KiB (8,786,400 / 8,794,116 /
|
||||
10,787,408 / 10,939,972). The two 1-thread repeats reproduce the corresponding
|
||||
sweep runs byte-for-byte in the compared artifacts: for 5G-NIDD,
|
||||
`test_global_metrics.json`, `val_selection.json`, `history.json`,
|
||||
`test_per_class.csv` and `per_client.csv` are identical to
|
||||
`results/sweep/runs/5gnidd__alpha0.5__seed0__support_weighted__beta0.75/...`
|
||||
(`sha256sum` equal for all five); for X-IIoTID the same is recorded by
|
||||
`compare_repro.json` (section 8.6). The 8-thread variants differ from the
|
||||
1-thread repeats (5G-NIDD rare macro-F1 0.875941789 vs 0.879314583; X-IIoTID
|
||||
0.643834668 vs 0.641979301).
|
||||
|
||||
---
|
||||
|
||||
## 4. All attempts, including failed and retried rows
|
||||
|
||||
Reconstructed from `results/sweep/logs/pool.log`,
|
||||
`results/sweep/logs/continuation.log`, per-run `logs/run.log`, and the orphan
|
||||
manifest. Filesystem timestamps quoted in UTC (`TZ=UTC stat`).
|
||||
|
||||
| run | attempt | started (UTC) | ended / outcome | evidence |
|
||||
|---|---:|---|---|---|
|
||||
| `5gnidd alpha0.25 beta1` | 1 | 2026-10-26T02:10:14Z | 2026-10-26T02:22:50Z, exit 143 (OOM) | `runs/...beta1/logs/run.log:3`, `pool.log:11`; journal OOM-kill |
|
||||
| `5gnidd alpha0.25 beta0` | 1 | 2026-10-26T02:10:14Z | 2026-10-26T02:22:53Z, exit 143 (OOM) | `runs/...beta0/logs/run.log:3`, `pool.log:16`; journal OOM-kill |
|
||||
| `xiiotid alpha0.25 beta0` | 1 | 2026-10-26T02:10:14Z | no END line, no COMPLETE; second attempt started 07:31:29Z | `logs/run.log` shows two START lines and no END for the first |
|
||||
| `xiiotid alpha0.25 beta1` | 1 | 2026-10-26T02:10:14Z | no END line, no COMPLETE; second attempt started 07:31:29Z | same |
|
||||
| `xiiotid alpha0.25 beta0.25` | 1 | 2026-10-26T02:22:51Z | orphan; result files written 2026-10-26T05:41:53Z, no `time.txt`, no COMPLETE | `_orphans_20261027T011213Z/` |
|
||||
| `5gnidd alpha0.25 beta0.25` | 1 | 2026-10-26T02:22:53Z | orphan; result files written 2026-10-26T07:29:08Z, no `time.txt`, no COMPLETE | `_orphans_20261027T011213Z/` |
|
||||
| `xiiotid alpha0.25 beta0.25` | 2 (gate) | gate started 2026-10-26T11:06:04Z | 2026-10-26T23:06:09Z, exit 4, "reference gate did not resolve within 12 h" | `pool.log:220`, inspection report |
|
||||
| `5gnidd alpha0.25 beta0.25` | 2 (gate) | gate started 2026-10-26T12:55:25Z | 2026-10-27T00:55:31Z, exit 4, same reason | `pool.log:50`, `pool.log:53`, `pool.log:253`; inspection report |
|
||||
| `xiiotid alpha0.5 beta0` | 1 (gate only) | gate from 2026-10-26T16:21:43Z | wrapper SIGTERMed 2026-10-27T01:06-01:07Z before training | `pool.log` gate lines, relaunch report |
|
||||
| `5gnidd alpha0.5 beta0` | 1 (gate only) | gate from 2026-10-26T23:06:09Z | wrapper SIGTERMed 2026-10-27T01:06-01:07Z before training | same |
|
||||
| `xiiotid alpha0.75 beta0` | 1 (gate only) | gate from 2026-10-27T00:55:31Z | wrapper SIGTERMed 2026-10-27T01:06-01:07Z before training | same |
|
||||
|
||||
All six configs above eventually appear as `completed` in `summary.csv` with the
|
||||
start times in section 3. The automatic retry pass at
|
||||
2026-10-28T18:00:12Z reported:
|
||||
|
||||
```
|
||||
[2026-10-28T18:00:12Z] RETRY: no failed rows; nothing to do
|
||||
[2026-10-28T18:00:12Z] SUPERVISOR retry pass finished rc=0
|
||||
[2026-10-28T18:00:12Z] SUPERVISOR done (main=0 retry=0)
|
||||
```
|
||||
|
||||
Orphan artifacts were moved (not deleted) to
|
||||
`results/sweep/_orphans_20261027T011213Z/` at 2026-10-27T01:12:13Z. The orphan
|
||||
manifest records, for the record only, test rare macro-F1 0.645839538
|
||||
(X-IIoTID beta0.25) and 0.887639250 (5G-NIDD beta0.25); attempt-1 wall time was
|
||||
never measured (`time.txt` 0 bytes). These are **not** the accepted results.
|
||||
|
||||
The manifest prints filesystem times in host local time (Europe/Berlin, UTC+1
|
||||
on 2026-10-26); the UTC values quoted above come from `TZ=UTC stat` on the same
|
||||
files and refer to the same inodes (identical nanosecond fractions).
|
||||
|
||||
---
|
||||
|
||||
## 5. Out-of-memory events
|
||||
|
||||
`journalctl -k` (kernel ring):
|
||||
|
||||
```
|
||||
$ journalctl -k --no-pager | grep -iE 'oom|out of memory|killed process'
|
||||
(no matching lines)
|
||||
```
|
||||
|
||||
`journalctl -b --utc -o short-iso` (systemd journal) contains:
|
||||
|
||||
```
|
||||
2026-10-26T02:01:37+00:00 aster systemd[2118]: run-r0a3b67e68dfa4510b7690d3eb1c285ef.scope: A process of this unit has been killed by the OOM killer.
|
||||
2026-10-26T02:01:37+00:00 aster systemd[2118]: run-r0a3b67e68dfa4510b7690d3eb1c285ef.scope: Failed with result 'oom-kill'.
|
||||
2026-10-26T02:01:37+00:00 aster systemd[2118]: app.slice: A process of this unit has been killed by the OOM killer.
|
||||
2026-10-26T02:22:50+00:00 aster systemd[2118]: run-r351421db66ec4b9dabb5153489c169a3.scope: A process of this unit has been killed by the OOM killer.
|
||||
2026-10-26T02:22:51+00:00 aster systemd[2118]: run-r351421db66ec4b9dabb5153489c169a3.scope: Failed with result 'oom-kill'.
|
||||
2026-10-26T02:22:53+00:00 aster systemd[2118]: run-r349991742c5d4469859a140260c1cc20.scope: A process of this unit has been killed by the OOM killer.
|
||||
2026-10-26T02:22:54+00:00 aster systemd[2118]: run-r349991742c5d4469859a140260c1cc20.scope: Failed with result 'oom-kill'.
|
||||
2026-10-26T07:29:09+00:00 aster systemd[2118]: app.slice: A process of this unit has been killed by the OOM killer.
|
||||
2026-10-28T11:11:37+00:00 aster systemd[2118]: -.slice: A process of this unit has been killed by the OOM killer.
|
||||
```
|
||||
|
||||
Interpretation limited to what the logs show:
|
||||
|
||||
- The 02:22:50 / 02:22:53 entries are the two 5G-NIDD first-wave run scopes;
|
||||
both rows recorded exit 143.
|
||||
- The 02:01:37 `run-r0a3b67e...` entry is before the queue started (pool start
|
||||
02:10:14). `launch_report.md` says the third kill in
|
||||
`/sys/fs/cgroup/user.slice/memory.events` is "most likely the earlier
|
||||
deliberate 512 MiB under a 200 MB cap test", i.e. not a queue row. That
|
||||
attribution is the launch report's inference; it is not independently
|
||||
confirmed here.
|
||||
- The 07:29:09 `app.slice` entry coincides with the end of the 5G-NIDD beta0.25
|
||||
orphan attempt; the log does not name a run.
|
||||
- The 2026-10-28T11:11:37 `-.slice` entry falls inside the completed
|
||||
`5gnidd alpha0.75 beta0.75` run window, which exited 0. No sweep `run.log`
|
||||
records a failure for it; its cause is not identified by these logs.
|
||||
- `dmesg` is not readable by this user:
|
||||
`dmesg: read kernel buffer failed: Operation not permitted`.
|
||||
|
||||
Sweep logs themselves contain no literal "OOM" string. The only failure markers
|
||||
are the two `END exit_code=143` lines in `pool.log`, each mirrored in the
|
||||
corresponding `runs/<run>/logs/run.log` (four lines in total).
|
||||
|
||||
---
|
||||
|
||||
## 6. Reference check against the pre-fixed tolerance
|
||||
|
||||
`results/sweep/reference_check.md` reports **Status: PASS**, generated
|
||||
`2026-10-27T01:10:36Z`. `results/sweep/reference_check.json` has
|
||||
`complete: true`, `stop: false`, `stop_reasons: []`, `missing_betas: []`.
|
||||
|
||||
Tolerance: the check compares each fresh value with the audit seed-0 value using
|
||||
a band of **+/- 2 x between-seed standard deviation** (`statistics.stdev`,
|
||||
ddof=1, over audit seeds 0,1,2). The comparison code is
|
||||
|
||||
```
|
||||
within = abs(delta) <= 2 * std
|
||||
```
|
||||
|
||||
and is identical in `reference_check.py.bak` (mtime
|
||||
`2026-10-26T02:06:56Z`) and the current `reference_check.py`. The first reference
|
||||
run started at `2026-10-26T02:10:14Z`, i.e. the tolerance predates the reference
|
||||
results. `launch_report.md` (mtime `2026-10-26T02:31:53Z`) also documents the
|
||||
2-sigma rule and was written before the reference runs finished (11:02Z / 11:06Z
|
||||
on 2026-10-26). The passing verdict itself was produced later, after a key-name
|
||||
fix at 2026-10-27T01:10:30Z.
|
||||
|
||||
Values (from `reference_check.json`):
|
||||
|
||||
| beta | metric | fresh | audit seed-0 | delta | z | 2-sigma band | within 2 sigma |
|
||||
|---:|---|---:|---:|---:|---:|---|---|
|
||||
| 0 | test rare macro-F1 | 0.641979301 | 0.641362228 | +0.000617073 | +0.013 | [0.546078671, 0.736645785] | true |
|
||||
| 0 | val rare macro-F1 (per-client mean) | 0.615114398 | 0.616380161 | -0.001265762 | -0.014 | [0.437322488, 0.795437834] | true |
|
||||
| 1 | test rare macro-F1 | 0.593073182 | 0.584131463 | +0.008941719 | +0.117 | [0.431612637, 0.736650288] | true |
|
||||
| 1 | val rare macro-F1 (per-client mean) | 0.579765280 | 0.578384529 | +0.001380751 | +0.030 | [0.486947852, 0.669821206] | true |
|
||||
|
||||
Both runs had `config_ok: true` and the expected loader content hash
|
||||
`839ba18e2d87245d198be8f5f89d4a24f13cdb6fc64c004d406c6d4f8246f3da`.
|
||||
|
||||
Earlier, `reference_check.py` crashed three times with
|
||||
`KeyError: 'val_rare_macro_f1_per_client_mean'`
|
||||
(`logs/reference_check.log`); this caused the 12-hour gate timeouts recorded in
|
||||
section 4. The crash and the fix are documented in
|
||||
`inspection_2026-10-27.md` and `relaunch_report.md`. These reports are inputs;
|
||||
their conclusions were not re-derived here.
|
||||
|
||||
---
|
||||
|
||||
## 7. Deviations from the original plan, with timestamps
|
||||
|
||||
1. **Per-process memory cap changed for 5G-NIDD (11 GiB -> 15 GiB).**
|
||||
The first wave used `MemoryMax=11G` for every run (`pool.log:6-9`). Two
|
||||
5G-NIDD runs were OOM-killed at 2026-10-26T02:22:50Z and 02:22:53Z.
|
||||
The in-flight 5G-NIDD beta0.25 scope was raised live to 15 GiB around
|
||||
02:23Z (per launch report), and `run_one.sh` was changed to select
|
||||
`5gnidd -> 15G`, others `-> 11G`; the pre-change backup
|
||||
`run_one.sh.bak` has mtime **2026-10-26T02:28:30Z**. The relaunched pool
|
||||
command lines show `MemoryMax=15G` for 5G-NIDD (`pool.log:26`, `33`, and
|
||||
later).
|
||||
2. **Pool size changed (P=4 -> P=3).**
|
||||
First pool: `P=4`, started **2026-10-26T02:10:14Z** (`pool.log:1`).
|
||||
Steady-state pool: `P=3`, started **2026-10-26T07:31:29Z** (`pool.log:20`).
|
||||
Final relaunch: `P=3`, pool start **2026-10-27T01:13:25Z**
|
||||
(`pool.log:263`; first run command at 01:13:26Z, `pool.log:274`).
|
||||
`pool.size` mtime 2026-10-27T01:13:25Z. P=5 was never used.
|
||||
3. **2-slot 5G-NIDD semaphore added to `run_one.sh`.**
|
||||
`run_one.sh` mtime **2026-10-27T01:10:59Z**; `pool.log` shows
|
||||
`SEMAPHORE acquired slot1/slot2` from the 01:13:26Z relaunch onward.
|
||||
4. **Reference-check bug fixed and gate guard added.**
|
||||
`reference_check.py` mtime **2026-10-27T01:10:30Z** (key names corrected).
|
||||
`run_one.sh` mtime **2026-10-27T01:10:59Z** (30-minute gate guard plus
|
||||
semaphore). `status.sh` mtime **2026-10-27T01:51:16Z** (cosmetic).
|
||||
5. **Retried / re-run rows.** `5gnidd alpha0.25 beta0` and `beta1` (OOM, first
|
||||
attempt 02:10:14Z, retried 07:31:29Z / 11:02:12Z); `xiiotid alpha0.25 beta0`
|
||||
and `beta1` (first attempt 02:10:14Z has no END, re-run 07:31:29Z);
|
||||
`xiiotid alpha0.25 beta0.25` and `5gnidd alpha0.25 beta0.25` (orphan attempt
|
||||
at 02:22:5xZ, gate attempt failed at 23:06:09Z / 00:55:31Z, final attempt
|
||||
01:13:26Z). See section 4 for evidence.
|
||||
6. **Gate-waiting processes were terminated before training.**
|
||||
At 2026-10-27T01:06-01:07Z the pool was stopped; three rows were waiting in
|
||||
the gate loop (`xiiotid 0.5`, `5gnidd 0.5`, `xiiotid 0.75`). They started
|
||||
later under the final relaunch. `pool.log:259-260` records the SIGTERM.
|
||||
7. **Orphan attempts moved aside.** `_orphans_20261027T011213Z/` created
|
||||
2026-10-27T01:12:13Z; no result file was deleted.
|
||||
8. **No queue row was skipped.** The 2026-10-21 5-thread smoke outputs were not
|
||||
accepted as sweep rows; all 30 configs were run under the 1-thread protocol.
|
||||
9. **Host timezone.** `timedatectl` reports `Europe/Berlin (CET, +0100)`; all
|
||||
timestamps in this report are UTC, converted with `journalctl --utc` or
|
||||
`TZ=UTC stat`. Some pre-existing sweep reports mix local and UTC times.
|
||||
|
||||
---
|
||||
|
||||
## 8. Outputs of the four analysis scripts
|
||||
|
||||
The four scripts were copied to `scripts/sweep/` and run against a scratch copy
|
||||
of the data (so the real `results/` was not written). Their outputs were
|
||||
byte-identical to the originals (section 9). The tables below are those outputs.
|
||||
|
||||
`analyze_sweep.py` writes three files. Stage 1 uses validation only; the test
|
||||
files are opened after `selection.csv` is written.
|
||||
|
||||
### 8.1 `selection.csv` (validation only, 30 rows)
|
||||
|
||||
The `selected` column is the script's stage-1 flag (highest
|
||||
`val_rare_class_macro_f1_per_client_mean`, ties to the smaller beta). It is
|
||||
reproduced as script output; this report does not adopt it.
|
||||
|
||||
| dataset | alpha | beta | val_rare_f1_per_client_mean | val_rare_f1_global | val_rare_recall_per_client_mean | val_macro_f1_global | selected | margin_to_runner_up |
|
||||
|---|---:|---:|---:|---:|---:|---:|---:|---:|
|
||||
| xiiotid | 0.25 | 0 | 0.615114398 | 0.643275275 | 0.846913348 | 0.676267875 | 0 | |
|
||||
| xiiotid | 0.25 | 0.25 | 0.612295414 | 0.647422433 | 0.847371095 | 0.680035834 | 0 | |
|
||||
| xiiotid | 0.25 | 0.5 | 0.590996277 | 0.632833153 | 0.831341674 | 0.667045341 | 0 | |
|
||||
| xiiotid | 0.25 | 0.75 | 0.656437133 | 0.669066681 | 0.870359212 | 0.699686253 | 1 | 0.041322734 |
|
||||
| xiiotid | 0.25 | 1 | 0.579765280 | 0.593760832 | 0.784814026 | 0.633116555 | 0 | |
|
||||
| xiiotid | 0.5 | 0 | 0.556929048 | 0.612060535 | 0.885829017 | 0.709691170 | 0 | |
|
||||
| xiiotid | 0.5 | 0.25 | 0.562538987 | 0.620452943 | 0.889189065 | 0.716471910 | 0 | |
|
||||
| xiiotid | 0.5 | 0.5 | 0.588286653 | 0.644186102 | 0.896470166 | 0.732532602 | 1 | 0.007362956 |
|
||||
| xiiotid | 0.5 | 0.75 | 0.580923697 | 0.636817927 | 0.889355473 | 0.726043174 | 0 | |
|
||||
| xiiotid | 0.5 | 1 | 0.558192955 | 0.614928577 | 0.857825220 | 0.714886486 | 0 | |
|
||||
| xiiotid | 0.75 | 0 | 0.497123071 | 0.532261516 | 0.766962632 | 0.748317495 | 0 | |
|
||||
| xiiotid | 0.75 | 0.25 | 0.499599429 | 0.526397734 | 0.756669120 | 0.748892418 | 0 | |
|
||||
| xiiotid | 0.75 | 0.5 | 0.499968468 | 0.513382502 | 0.765223179 | 0.741108809 | 1 | 0.000369040 |
|
||||
| xiiotid | 0.75 | 0.75 | 0.490886014 | 0.510831286 | 0.761348983 | 0.741545715 | 0 | |
|
||||
| xiiotid | 0.75 | 1 | 0.477724598 | 0.507546185 | 0.762276080 | 0.741271747 | 0 | |
|
||||
| 5gnidd | 0.25 | 0 | 0.732063562 | 0.863288898 | 0.888413711 | 0.833210589 | 0 | |
|
||||
| 5gnidd | 0.25 | 0.25 | 0.750234422 | 0.887687791 | 0.886155769 | 0.849340729 | 1 | 0.015462491 |
|
||||
| 5gnidd | 0.25 | 0.5 | 0.715027757 | 0.818058015 | 0.885062004 | 0.804059192 | 0 | |
|
||||
| 5gnidd | 0.25 | 0.75 | 0.711752341 | 0.795364214 | 0.877813860 | 0.802485891 | 0 | |
|
||||
| 5gnidd | 0.25 | 1 | 0.734771931 | 0.801655038 | 0.874817852 | 0.818441666 | 0 | |
|
||||
| 5gnidd | 0.5 | 0 | 0.739471675 | 0.867651737 | 0.964727218 | 0.835451455 | 0 | |
|
||||
| 5gnidd | 0.5 | 0.25 | 0.657948994 | 0.826207029 | 0.964727218 | 0.799036116 | 0 | |
|
||||
| 5gnidd | 0.5 | 0.5 | 0.731662212 | 0.862708327 | 0.964727218 | 0.836388230 | 0 | |
|
||||
| 5gnidd | 0.5 | 0.75 | 0.771920820 | 0.875152730 | 0.964727218 | 0.849873996 | 1 | 0.005265685 |
|
||||
| 5gnidd | 0.5 | 1 | 0.766655135 | 0.876266492 | 0.964727218 | 0.846137526 | 0 | |
|
||||
| 5gnidd | 0.75 | 0 | 0.836358274 | 0.896193888 | 0.964226565 | 0.851335066 | 0 | |
|
||||
| 5gnidd | 0.75 | 0.25 | 0.849565876 | 0.902762083 | 0.964226565 | 0.856336364 | 1 | 0.013207603 |
|
||||
| 5gnidd | 0.75 | 0.5 | 0.830443462 | 0.901146966 | 0.963185589 | 0.855355109 | 0 | |
|
||||
| 5gnidd | 0.75 | 0.75 | 0.815299394 | 0.897742377 | 0.963715390 | 0.853576206 | 0 | |
|
||||
| 5gnidd | 0.75 | 1 | 0.808079811 | 0.894306659 | 0.965304794 | 0.851265425 | 0 | |
|
||||
|
||||
### 8.2 `test_at_selected_beta.csv` (test, 30 rows)
|
||||
|
||||
`selected_on_validation` marks the beta flagged in 8.1. `test_rare_support` is
|
||||
the number of test samples in the rare classes.
|
||||
|
||||
| dataset | alpha | beta | selected_on_validation | test_rare_f1_global | test_rare_recall_global | test_macro_f1 | test_accuracy | test_rare_support |
|
||||
|---|---:|---:|---:|---:|---:|---:|---:|---:|
|
||||
| xiiotid | 0.25 | 0 | 0 | 0.641979301 | 0.830387426 | 0.675034969 | 0.873838520 | 79180 |
|
||||
| xiiotid | 0.25 | 0.25 | 0 | 0.645839538 | 0.824822512 | 0.678550791 | 0.868704362 | 79180 |
|
||||
| xiiotid | 0.25 | 0.5 | 0 | 0.631488471 | 0.793292581 | 0.665776684 | 0.854517874 | 79180 |
|
||||
| xiiotid | 0.25 | 0.75 | 1 | 0.669170594 | 0.794023733 | 0.699726946 | 0.855561902 | 79180 |
|
||||
| xiiotid | 0.25 | 1 | 0 | 0.593073182 | 0.704711149 | 0.632415448 | 0.849138063 | 79180 |
|
||||
| xiiotid | 0.5 | 0 | 0 | 0.613084485 | 0.871186482 | 0.710555367 | 0.896929946 | 25454 |
|
||||
| xiiotid | 0.5 | 0.25 | 0 | 0.622176085 | 0.873858741 | 0.717774657 | 0.897568645 | 25454 |
|
||||
| xiiotid | 0.5 | 0.5 | 1 | 0.643904823 | 0.874747143 | 0.732555353 | 0.898287181 | 25454 |
|
||||
| xiiotid | 0.5 | 0.75 | 0 | 0.636012409 | 0.863519815 | 0.725833853 | 0.886133476 | 25454 |
|
||||
| xiiotid | 0.5 | 1 | 0 | 0.615308344 | 0.838787843 | 0.715340930 | 0.881257254 | 25454 |
|
||||
| xiiotid | 0.75 | 0 | 0 | 0.526279577 | 0.819166043 | 0.745053791 | 0.912854432 | 6251 |
|
||||
| xiiotid | 0.75 | 0.25 | 0 | 0.520979721 | 0.806403017 | 0.745946340 | 0.916207602 | 6251 |
|
||||
| xiiotid | 0.75 | 0.5 | 1 | 0.506784362 | 0.796163189 | 0.737595025 | 0.911871818 | 6251 |
|
||||
| xiiotid | 0.75 | 0.75 | 0 | 0.507162154 | 0.807061731 | 0.739196779 | 0.913057096 | 6251 |
|
||||
| xiiotid | 0.75 | 1 | 0 | 0.504951940 | 0.817143701 | 0.739630728 | 0.911939373 | 6251 |
|
||||
| 5gnidd | 0.25 | 0 | 0 | 0.861244967 | 0.984948540 | 0.832176777 | 0.744659240 | 141677 |
|
||||
| 5gnidd | 0.25 | 0.25 | 1 | 0.887639250 | 0.980086383 | 0.850377106 | 0.740711498 | 141677 |
|
||||
| 5gnidd | 0.25 | 0.5 | 0 | 0.818078455 | 0.977174954 | 0.804997750 | 0.740863651 | 141677 |
|
||||
| 5gnidd | 0.25 | 0.75 | 0 | 0.795982829 | 0.949513575 | 0.804428539 | 0.730101942 | 141677 |
|
||||
| 5gnidd | 0.25 | 1 | 0 | 0.802243321 | 0.935212949 | 0.819876826 | 0.752912488 | 141677 |
|
||||
| 5gnidd | 0.5 | 0 | 0 | 0.869410144 | 0.974261201 | 0.836168314 | 0.735143537 | 104843 |
|
||||
| 5gnidd | 0.5 | 0.25 | 0 | 0.827176768 | 0.974219638 | 0.799716621 | 0.728399479 | 104843 |
|
||||
| 5gnidd | 0.5 | 0.5 | 0 | 0.868956930 | 0.974261221 | 0.840088463 | 0.739103616 | 104843 |
|
||||
| 5gnidd | 0.5 | 0.75 | 1 | 0.879314583 | 0.974272043 | 0.853591585 | 0.745403554 | 104843 |
|
||||
| 5gnidd | 0.5 | 1 | 0 | 0.878757266 | 0.974272032 | 0.848514697 | 0.741887596 | 104843 |
|
||||
| 5gnidd | 0.75 | 0 | 0 | 0.902386981 | 0.959484554 | 0.855113260 | 0.747373312 | 28000 |
|
||||
| 5gnidd | 0.75 | 0.25 | 1 | 0.906545156 | 0.960038373 | 0.858596769 | 0.749429428 | 28000 |
|
||||
| 5gnidd | 0.75 | 0.5 | 0 | 0.904655697 | 0.958552306 | 0.857440422 | 0.749585693 | 28000 |
|
||||
| 5gnidd | 0.75 | 0.75 | 0 | 0.901701106 | 0.960284499 | 0.855855667 | 0.750461598 | 28000 |
|
||||
| 5gnidd | 0.75 | 1 | 0 | 0.899195897 | 0.964090767 | 0.854143914 | 0.750432812 | 28000 |
|
||||
|
||||
### 8.3 `repro_vs_previous.csv` (30 rows, absolute differences)
|
||||
|
||||
Differences are `|new - previous grid|`; the script prints them with three
|
||||
significant digits. "new" is the 1-thread sweep run; "previous" is the earlier
|
||||
grid run at the same `(dataset, alpha, seed0, beta)`.
|
||||
|
||||
| dataset | alpha | beta | test_rare_f1_new | test_rare_f1_prev | abs_diff_test_rare_f1 | abs_diff_test_macro_f1 | abs_diff_test_accuracy | abs_diff_val_sel_metric |
|
||||
|---|---:|---:|---:|---:|---:|---:|---:|---:|
|
||||
| xiiotid | 0.25 | 0 | 0.641979301 | 0.641362228 | 6.171e-04 | 4.767e-04 | 7.124e-04 | 1.266e-03 |
|
||||
| xiiotid | 0.25 | 0.25 | 0.645839538 | 0.645064558 | 7.750e-04 | 7.555e-04 | 2.070e-03 | 2.383e-03 |
|
||||
| xiiotid | 0.25 | 0.5 | 0.631488471 | 0.631742435 | 2.540e-04 | 1.888e-04 | 1.302e-03 | 4.251e-03 |
|
||||
| xiiotid | 0.25 | 0.75 | 0.669170594 | 0.666176967 | 2.994e-03 | 2.684e-03 | 9.151e-04 | 2.404e-03 |
|
||||
| xiiotid | 0.25 | 1 | 0.593073182 | 0.584131463 | 8.942e-03 | 7.927e-03 | 2.045e-03 | 1.381e-03 |
|
||||
| xiiotid | 0.5 | 0 | 0.613084485 | 0.613575398 | 4.909e-04 | 7.455e-05 | 4.956e-03 | 4.106e-04 |
|
||||
| xiiotid | 0.5 | 0.25 | 0.622176085 | 0.632154112 | 9.978e-03 | 7.525e-03 | 5.951e-03 | 9.248e-03 |
|
||||
| xiiotid | 0.5 | 0.5 | 0.643904823 | 0.640829406 | 3.075e-03 | 1.813e-03 | 1.290e-04 | 2.525e-03 |
|
||||
| xiiotid | 0.5 | 0.75 | 0.636012409 | 0.636188757 | 1.763e-04 | 4.646e-04 | 2.536e-03 | 2.921e-03 |
|
||||
| xiiotid | 0.5 | 1 | 0.615308344 | 0.615509445 | 2.011e-04 | 1.042e-03 | 3.378e-03 | 6.750e-03 |
|
||||
| xiiotid | 0.75 | 0 | 0.526279577 | 0.525867706 | 4.119e-04 | 6.807e-04 | 8.905e-04 | 3.200e-04 |
|
||||
| xiiotid | 0.75 | 0.25 | 0.520979721 | 0.520851745 | 1.280e-04 | 7.959e-04 | 1.069e-03 | 2.708e-03 |
|
||||
| xiiotid | 0.75 | 0.5 | 0.506784362 | 0.511888897 | 5.105e-03 | 4.382e-03 | 2.493e-03 | 4.419e-03 |
|
||||
| xiiotid | 0.75 | 0.75 | 0.507162154 | 0.502310077 | 4.852e-03 | 2.765e-03 | 7.799e-04 | 4.018e-03 |
|
||||
| xiiotid | 0.75 | 1 | 0.504951940 | 0.506063809 | 1.112e-03 | 2.007e-04 | 1.535e-03 | 1.421e-03 |
|
||||
| 5gnidd | 0.25 | 0 | 0.861244967 | 0.859892744 | 1.352e-03 | 2.497e-03 | 1.851e-04 | 4.297e-03 |
|
||||
| 5gnidd | 0.25 | 0.25 | 0.887639250 | 0.885537113 | 2.102e-03 | 5.700e-04 | 1.147e-03 | 2.936e-03 |
|
||||
| 5gnidd | 0.25 | 0.5 | 0.818078455 | 0.824837056 | 6.759e-03 | 3.770e-03 | 3.742e-03 | 2.423e-03 |
|
||||
| 5gnidd | 0.25 | 0.75 | 0.795982829 | 0.804422938 | 8.440e-03 | 2.071e-03 | 1.871e-02 | 1.510e-03 |
|
||||
| 5gnidd | 0.25 | 1 | 0.802243321 | 0.805922621 | 3.679e-03 | 2.820e-03 | 1.398e-03 | 3.167e-04 |
|
||||
| 5gnidd | 0.5 | 0 | 0.869410144 | 0.874293205 | 4.883e-03 | 2.393e-03 | 2.920e-04 | 8.742e-04 |
|
||||
| 5gnidd | 0.5 | 0.25 | 0.827176768 | 0.827855971 | 6.792e-04 | 5.151e-03 | 3.763e-03 | 3.512e-03 |
|
||||
| 5gnidd | 0.5 | 0.5 | 0.868956930 | 0.878225000 | 9.268e-03 | 4.119e-03 | 1.583e-03 | 3.283e-02 |
|
||||
| 5gnidd | 0.5 | 0.75 | 0.879314583 | 0.866626856 | 1.269e-02 | 5.548e-03 | 1.361e-03 | 2.126e-02 |
|
||||
| 5gnidd | 0.5 | 1 | 0.878757266 | 0.880962035 | 2.205e-03 | 1.955e-03 | 9.499e-04 | 2.222e-03 |
|
||||
| 5gnidd | 0.75 | 0 | 0.902386981 | 0.900366644 | 2.020e-03 | 1.505e-03 | 4.811e-04 | 1.677e-03 |
|
||||
| 5gnidd | 0.75 | 0.25 | 0.906545156 | 0.901681021 | 4.864e-03 | 3.485e-03 | 9.129e-04 | 2.618e-02 |
|
||||
| 5gnidd | 0.75 | 0.5 | 0.904655697 | 0.904447205 | 2.085e-04 | 1.315e-04 | 7.813e-05 | 6.348e-03 |
|
||||
| 5gnidd | 0.75 | 0.75 | 0.901701106 | 0.904214210 | 2.513e-03 | 1.576e-03 | 1.398e-04 | 9.367e-03 |
|
||||
| 5gnidd | 0.75 | 1 | 0.899195897 | 0.900797707 | 1.602e-03 | 1.031e-03 | 2.879e-05 | 7.694e-03 |
|
||||
|
||||
### 8.4 `check_noise.py` -> `noise_checks.json` (excerpt)
|
||||
|
||||
The full file is 380 lines (379 newlines; no trailing newline) and was written
|
||||
unchanged. Key blocks:
|
||||
|
||||
- `A_summary.first_round_with_difference_counts`: `{"0": 30}` — every paired run
|
||||
first differs from the earlier grid in round 0, and
|
||||
`n_samples_equal_all_rounds` is `true` for all 30 pairs.
|
||||
- `B_sign.test_rare_f1`: n=30, sweep higher 14, lower 16, mean signed diff
|
||||
-0.0004104998, mean absolute diff 0.0034124859. The script labels its
|
||||
two-sided sign-test p-value `0.8555355519` as
|
||||
`NOT_independent_pairs`; the 30 pairs share partitions across betas. This
|
||||
report does not interpret it.
|
||||
- `B_sign.val_selection_metric`: n=30, sweep higher 15, lower 15, mean signed
|
||||
diff -0.0004188014, mean absolute diff 0.0056621689; script p-value
|
||||
`1.0`, again labelled as non-independent.
|
||||
- `C_rank` (rank stability, sweep vs earlier seed-0 grid over 5 betas):
|
||||
|
||||
| dataset | alpha | spearman | max_abs_val_diff | betas_within_max_diff_of_sweep_best |
|
||||
|---|---:|---:|---:|---|
|
||||
| xiiotid | 0.25 | 1.0 | 0.004251150 | `0.75` |
|
||||
| xiiotid | 0.5 | 0.9 | 0.009248424 | `0.5`, `0.75` |
|
||||
| xiiotid | 0.75 | 1.0 | 0.004419246 | `0`, `0.25`, `0.5` |
|
||||
| 5gnidd | 0.25 | 0.9 | 0.004296561 | `0.25` |
|
||||
| 5gnidd | 0.5 | 0.5 | 0.032825056 | `0`, `0.75`, `1` |
|
||||
| 5gnidd | 0.75 | 0.3 | 0.026177811 | `0`, `0.25`, `0.5` |
|
||||
|
||||
### 8.5 `compare_with_grid.py` -> `compare_with_grid.csv` (6 rows)
|
||||
|
||||
The `beta_*` columns are script output (validation-only ranking), not a
|
||||
recommendation.
|
||||
|
||||
| dataset | alpha | beta_sweep_seed0 | beta_grid_seed0 | beta_grid_pooled | sweep_equals_grid_s0 | sweep_equals_pooled | grid_s0_equals_pooled | sweep_margin | grid_s0_margin | max_abs_val_diff_s0 | sweep_pick_rank_in_grid_s0 |
|
||||
|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|
||||
| xiiotid | 0.25 | 0.75 | 0.75 | 0.0 | 1 | 0 | 0 | 0.041323 | 0.037653 | 0.004251 | 1 |
|
||||
| xiiotid | 0.5 | 0.5 | 0.5 | 0.75 | 1 | 0 | 0 | 0.007363 | 0.007759 | 0.009248 | 1 |
|
||||
| xiiotid | 0.75 | 0.5 | 0.5 | 0.5 | 1 | 1 | 1 | 0.000369 | 0.007496 | 0.004419 | 1 |
|
||||
| 5gnidd | 0.25 | 0.25 | 0.25 | 0.0 | 1 | 0 | 0 | 0.015462 | 0.010939 | 0.004297 | 1 |
|
||||
| 5gnidd | 0.5 | 0.75 | 1.0 | 1.0 | 0 | 0 | 1 | 0.005266 | 0.004390 | 0.032825 | 3 |
|
||||
| 5gnidd | 0.75 | 0.25 | 0.5 | 0.5 | 0 | 0 | 1 | 0.013208 | 0.002110 | 0.026178 | 4 |
|
||||
|
||||
### 8.6 `compare_repro.py` -> `compare_repro.json` and stdout
|
||||
|
||||
Printed table:
|
||||
|
||||
```
|
||||
a_1thread_repeat__vs__sweep test_rare=0.000e+00 val_sel=0.000e+00 round0=0.000e+00 last=0.000e+00 all_json_equal=True snapshot_identical=True
|
||||
b_8thread__vs__grid test_rare=2.472e-03 val_sel=8.021e-04 round0=4.840e-05 last=2.242e-03 all_json_equal=False snapshot_identical=False
|
||||
a_1thread_repeat__vs__grid test_rare=6.171e-04 val_sel=1.266e-03 round0=4.552e-05 last=3.359e-04 all_json_equal=False snapshot_identical=False
|
||||
b_8thread__vs__sweep test_rare=1.855e-03 val_sel=4.637e-04 round0=9.392e-05 last=1.906e-03 all_json_equal=False snapshot_identical=False
|
||||
sweep__vs__grid test_rare=6.171e-04 val_sel=1.266e-03 round0=4.552e-05 last=3.359e-04 all_json_equal=False snapshot_identical=False
|
||||
a_1thread_repeat__vs__b_8thread test_rare=1.855e-03 val_sel=4.637e-04 round0=9.392e-05 last=1.906e-03 all_json_equal=False snapshot_identical=False
|
||||
```
|
||||
|
||||
Facts recorded in the JSON:
|
||||
|
||||
- `a_1thread_repeat` vs `sweep`: all four JSON files byte-identical and
|
||||
JSON-equal; prototype snapshot byte-identical; test rare F1 and validation
|
||||
metric differences 0.0; all ten per-round rare-F1 differences 0.0.
|
||||
- `b_8thread` vs `grid`: JSON files not byte-identical; test rare F1
|
||||
b_8thread 0.643834668 vs grid 0.641362228, abs diff 0.002472440; validation
|
||||
metric abs diff 0.000802084; prototype snapshot differs.
|
||||
- `a_1thread_repeat` vs `grid`: test rare F1 0.641979301 vs 0.641362228,
|
||||
abs diff 0.000617073; validation metric abs diff 0.001265762.
|
||||
- The remaining pairs are context and show the same pattern (different
|
||||
runs differ; the repeated 1-thread run is identical to the sweep run).
|
||||
|
||||
This script analyses only the X-IIoTID `alpha0.25 seed0 beta0` pair. A second
|
||||
reproducibility pair exists under
|
||||
`results/sweep_repro/5gnidd_a0.5_b0.75/` (5G-NIDD `alpha0.5 seed0 beta0.75`,
|
||||
1-thread and 8-thread). `compare_repro.py` does not analyse it; its wall time,
|
||||
peak RSS and the byte-identical 1-thread comparison are reported in section 3.1.
|
||||
|
||||
---
|
||||
|
||||
## 9. Scripts moved into version control
|
||||
|
||||
Commit on branch `chore/posthoc-audit-and-docs-refresh`:
|
||||
|
||||
```
|
||||
9fe584d08e0471ed517cb6f781e522f99d002520
|
||||
chore: version-control sweep analysis scripts
|
||||
```
|
||||
|
||||
Pushed without force (`e66ecc4..9fe584d`); after the push `HEAD` and
|
||||
`origin/chore/posthoc-audit-and-docs-refresh` both pointed at
|
||||
`9fe584d08e0471ed517cb6f781e522f99d002520`. `main` and `origin/main` both
|
||||
remained at `34bab458651b80c617490a75b94b27fdcbbc19fb`, and `9fe584d` is not an
|
||||
ancestor of `main`.
|
||||
|
||||
Files added (5 files, 697 insertions):
|
||||
|
||||
```
|
||||
scripts/sweep/README.md
|
||||
scripts/sweep/analyze_sweep.py
|
||||
scripts/sweep/check_noise.py
|
||||
scripts/sweep/compare_repro.py
|
||||
scripts/sweep/compare_with_grid.py
|
||||
```
|
||||
|
||||
The originals remain in `results/sweep/` and `results/sweep_repro/`. The copies
|
||||
change only path resolution: a `--repo-root` argument with a default of
|
||||
`<repo>/` derived from `scripts/sweep/` (the originals derived the root from
|
||||
their old location inside `results/`). No computation was changed.
|
||||
|
||||
Equivalence was tested on a scratch copy of the data
|
||||
(`~/restore_work/sweep_scripts_check`), not on the real `results/`. Original
|
||||
scripts were run from a mirrored `results/sweep/` layout; copies were run with
|
||||
`--repo-root`. Comparison:
|
||||
|
||||
```
|
||||
IDENTICAL results/sweep/analysis/selection.csv 37df4e7b13fedf3436c04697fa7660125e08118e14fe4786ac67bcd546c43ac7
|
||||
IDENTICAL results/sweep/analysis/test_at_selected_beta.csv df68a30929c59c76773c92323fcdbd30dfdb8bb5de3366dd05dc7a4819b70614
|
||||
IDENTICAL results/sweep/analysis/repro_vs_previous.csv 408bfac4b324e00bc21362fb3766df6208d8787eae3612428f229f8aa7426696
|
||||
IDENTICAL results/sweep/analysis/noise_checks.json c23509183a8c69f4584b8d09083f4dd0c0ef10a1b63dba62e1677ab52375b38a
|
||||
IDENTICAL results/sweep/analysis/compare_with_grid.csv b995d8541134ee3522a5f28aa4cae097b68e2cd28b2c6fd82bc3ce5c4f04c48d
|
||||
IDENTICAL results/sweep_repro/compare_repro.json 9d2e73c4021aceb89925f879100f562db8e5e996bcbe043f443d369ac088317c
|
||||
```
|
||||
|
||||
Stdout tables were identical after normalizing only the printed root path
|
||||
(`data_orig` vs `data_new`); the only textual difference was the path in the
|
||||
"written ..." lines. Running the copies with the default root also reproduced
|
||||
the same six files. The same six hashes were also compared with the on-disk
|
||||
`results/` outputs and matched (`MATCH` for all six). The committed copies are
|
||||
byte-identical to the copies used in that scratch run (`diff` reported no
|
||||
difference for all four scripts). At the end of this session all four copies
|
||||
were re-run on the scratch mirror with the repository virtualenv, e.g.
|
||||
|
||||
```
|
||||
$ .venv/bin/python data_new/scripts/sweep/analyze_sweep.py --repo-root data_new
|
||||
```
|
||||
|
||||
Each returned `rc=0`, and the six output files again hashed exactly as in the
|
||||
block above; stdout was identical to the original scripts after normalizing the
|
||||
mirror directory name (`data_orig` vs `data_new`).
|
||||
|
||||
The existing test suite was run with the repository virtualenv (system
|
||||
`python3` has no `pytest` or `numpy`, so `python3 -m pytest` fails with
|
||||
`No module named pytest`; the venv is `.venv/`). It was run after the commit
|
||||
was pushed; the commit contains no test or source changes beyond the five files
|
||||
listed above:
|
||||
|
||||
```
|
||||
$ PYTHONDONTWRITEBYTECODE=1 .venv/bin/python -m pytest -q -p no:cacheprovider
|
||||
........................................................................ [ 96%]
|
||||
... [100%]
|
||||
$ echo $?
|
||||
0
|
||||
```
|
||||
|
||||
75 test nodes ran, all passed (75 `.`, 0 `F`, 0 `E`, 0 `s`), exit code 0.
|
||||
`python3 -m py_compile scripts/sweep/*.py` also succeeded (`rc=0`; the
|
||||
resulting `scripts/sweep/__pycache__/` was removed afterwards, so the working
|
||||
tree contains only the five committed files).
|
||||
|
||||
Write-target check: the only write sites in the copies are
|
||||
`results/sweep/analysis/*` (three files from `analyze_sweep.py`,
|
||||
`noise_checks.json` from `check_noise.py`, `compare_with_grid.csv` from
|
||||
`compare_with_grid.py`) and
|
||||
`results/sweep_repro/compare_repro.json`. `git ls-files results/` is empty, so
|
||||
none of these is tracked. The scratch runs wrote only inside
|
||||
`~/restore_work/sweep_scripts_check/`.
|
||||
|
||||
Credential/privacy scan: the staged files were scanned before the commit, and
|
||||
the committed blobs were re-scanned during this session with
|
||||
`git show HEAD:scripts/sweep/<file>` concatenated into one 697-line stream:
|
||||
|
||||
```
|
||||
$ grep -cEi '(api[_-]?key|secret|access[_-]?token|auth[_-]?token|password|passwd|credential|bearer |private[_-]?key|BEGIN [A-Z ]*PRIVATE KEY|ssh-rsa|ssh-ed25519|ghp_|github_pat_|AKIA[0-9A-Z]{16}|xox[baprs]-)' <stream>
|
||||
0 # grep exit code 1
|
||||
$ grep -cE '(/home/|/Users/|/root/|~/|localhost|github-thesis|willtanoe|([0-9]{1,3}\.){3}[0-9]{1,3})' <stream>
|
||||
0 # grep exit code 1
|
||||
```
|
||||
|
||||
Both scans returned **0 matches**. The generic high-entropy scan matched
|
||||
only identifier-like strings such as
|
||||
`val_rare_class_macro_f1_per_client_mean` and path fragments
|
||||
`results/sweep_repro/a_1thread_repeat/...`; these are not credentials. A
|
||||
case-insensitive scan for `aster` matched the substring in "master" in
|
||||
`compare_with_grid.py` (`final__six_condition_master.csv`), not a hostname.
|
||||
|
||||
---
|
||||
|
||||
## 10. Server-side hashes
|
||||
|
||||
`~/restore_work/final_hashes.txt` contains the sorted SHA-256 list of every file
|
||||
under `results/sweep/` and `results/sweep_repro/` on this server.
|
||||
|
||||
Command used:
|
||||
|
||||
```
|
||||
find results/sweep results/sweep_repro -type f -print0 \
|
||||
| xargs -0 sha256sum | LC_ALL=C sort -k2
|
||||
```
|
||||
|
||||
- Files hashed: **912** (`results/sweep`: 818, `results/sweep_repro`: 94).
|
||||
- Hashing was done in two complete independent passes, both finishing
|
||||
2026-10-29T17:21:11Z. `diff pass1 pass2` reported no differences, so **no
|
||||
file changed during hashing** and the file set did not change between passes
|
||||
(the file header states this explicitly).
|
||||
- At hashing time `results/sweep/PHASE` was `done`, the last heartbeat was
|
||||
`2026-10-29T00:02:03Z`, and no `run_one.sh` / `xargs` / `launch_all` process
|
||||
was running.
|
||||
- The written manifest was read back with `sha256sum -c`: **912 OK, 0 failures**
|
||||
(`verify rc=0`) at 2026-10-29T17:21:20Z, and again at the end of the session
|
||||
at 2026-10-29T17:27:50Z with the same result (912 OK, 0 failures, file count
|
||||
still 912). Nothing under `results/` was written by this session.
|
||||
- The manifest itself is not committed (it lives in `~/restore_work/`, outside
|
||||
the repository).
|
||||
|
||||
---
|
||||
|
||||
## 11. Open issues / unverified items
|
||||
|
||||
1. **Test suite required the repository virtualenv.** `.venv/bin/python -m
|
||||
pytest` passes (75 tests); the system `python3 -m pytest` fails with
|
||||
`No module named pytest`. Nothing was installed to change that.
|
||||
2. **First attempts of `xiiotid alpha0.25 beta0/beta1` have no END line and no
|
||||
measured wall time.** Their run directories were overwritten by the
|
||||
07:31:29Z re-run; the cause of the missing END is not recorded in the logs.
|
||||
3. **The 2026-10-28T11:11:37Z `-.slice` OOM entry is unattributed.** It falls
|
||||
inside a run that exited 0; no sweep log records a failure for it.
|
||||
4. **`dmesg` is unreadable (EPERM);** OOM evidence is limited to
|
||||
`journalctl -b`.
|
||||
5. **The reference check's PASS verdict was produced after a bug fix,** not by
|
||||
the original crash-prone invocation. The tolerance itself predates the
|
||||
results (`reference_check.py.bak`, 2026-10-26T02:06:56Z; first reference run
|
||||
02:10:14Z).
|
||||
6. **Single seed.** The sweep is seed 0 only. No between-seed claim is made.
|
||||
7. **The 5G-NIDD beta0.25 live cap raise is not reproducible from logs alone**
|
||||
(the run.log still shows the 11G launch command); this is noted in the
|
||||
pre-existing launch report.
|
||||
8. **Report is not committed.** `kisikisithesis/SWEEP_SUMMARY_REPORT.md` is
|
||||
untracked and is not part of commit `9fe584d`.
|
||||
9. `results/` was not modified by this session; the analysis scripts were run
|
||||
only against the scratch copy. The pre-existing on-disk analysis outputs
|
||||
matched the fresh scratch outputs.
|
||||
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Deterministic, read-only robustness checks for the PROTEAN thesis.
|
||||
|
||||
Run from the repository root:
|
||||
|
||||
.venv/bin/python kisikisithesis/robustness_checks.py
|
||||
|
||||
Nothing is written and no experimental artifact is modified. The script:
|
||||
* exercises the *actual* aggregation implementation on tiny synthetic inputs
|
||||
(formula invariants);
|
||||
* recomputes direct aggregation effects on persisted round-0 prototype
|
||||
snapshots (no training, no snapshot mutation).
|
||||
|
||||
All values are printed deterministically so the thesis report can quote them.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / "src"))
|
||||
|
||||
from protean_research.aggregation.prototype_aggregation import ( # noqa: E402
|
||||
AggregationMode,
|
||||
aggregate_prototypes,
|
||||
aggregate_class_prototypes,
|
||||
normalized_support_weights,
|
||||
validate_beta,
|
||||
BETA_CANDIDATES,
|
||||
)
|
||||
from protean_research.analysis.direct_prototype import ( # noqa: E402
|
||||
client_weight_rows,
|
||||
prototype_effect_rows,
|
||||
)
|
||||
|
||||
ANALYSIS = ROOT / "artifacts" / "analysis"
|
||||
|
||||
|
||||
def section(title: str) -> None:
|
||||
print("\n" + "=" * 74)
|
||||
print(title)
|
||||
print("=" * 74)
|
||||
|
||||
|
||||
def check(label: str, ok: bool) -> None:
|
||||
print(f" [{'PASS' if ok else 'FAIL'}] {label}")
|
||||
|
||||
|
||||
def synthetic_invariants() -> None:
|
||||
section("A. Synthetic formula invariants (actual implementation)")
|
||||
p = [[1.0, 0.0], [0.0, 2.0], [3.0, 3.0]]
|
||||
s = [5.0, 10.0, 20.0]
|
||||
|
||||
eq = [sum(v[d] for v in p) / len(p) for d in range(2)]
|
||||
b0 = aggregate_prototypes(p, AggregationMode.SUPPORT_WEIGHTED, supports=s, beta=0.0)
|
||||
print(f" beta=0 aggregate = {b0}")
|
||||
print(f" arithmetic mean = {eq}")
|
||||
check("beta=0 equals the arithmetic mean over S_j",
|
||||
all(abs(a - b) < 1e-12 for a, b in zip(b0, eq)))
|
||||
|
||||
w1 = normalized_support_weights(s, 1.0)
|
||||
b1 = aggregate_prototypes(p, AggregationMode.SUPPORT_WEIGHTED, supports=s, beta=1.0)
|
||||
closed = [sum(w * v[d] for w, v in zip(w1, p)) for d in range(2)]
|
||||
print(f" beta=1 weights = {[round(w, 6) for w in w1]}")
|
||||
print(f" beta=1 aggregate = {b1}")
|
||||
check("beta=1 equals the support-weighted closed form",
|
||||
all(abs(a - b) < 1e-12 for a, b in zip(b1, closed)))
|
||||
|
||||
w05 = normalized_support_weights(s, 0.5)
|
||||
b05 = aggregate_prototypes(p, AggregationMode.SUPPORT_WEIGHTED, supports=s, beta=0.5)
|
||||
print(f" beta=0.5 weights = {[round(w, 6) for w in w05]}")
|
||||
print(f" beta=0.5 aggregate = {b05}")
|
||||
|
||||
single = aggregate_prototypes([[7.0, 9.0]], AggregationMode.SUPPORT_WEIGHTED,
|
||||
supports=[3.0], beta=1.0)
|
||||
check("single contributor is beta-invariant", single == [7.0, 9.0])
|
||||
|
||||
equal = [aggregate_prototypes(p, AggregationMode.SUPPORT_WEIGHTED,
|
||||
supports=[4.0, 4.0, 4.0], beta=b) for b in BETA_CANDIDATES]
|
||||
check("equal support is beta-invariant", all(g == equal[0] for g in equal))
|
||||
|
||||
for b in BETA_CANDIDATES:
|
||||
tot = sum(normalized_support_weights(s, b))
|
||||
if abs(tot - 1.0) > 1e-12:
|
||||
check(f"weights sum to 1 at beta={b}", False)
|
||||
break
|
||||
else:
|
||||
check("normalized weights sum to 1 for every beta candidate", True)
|
||||
|
||||
# zero-support exclusion and missing-class handling through the S_j builder
|
||||
contributions = {0: [([1.0], 5.0), ([2.0], 0.0), (None, 7.0)], 1: [(None, 0.0)]}
|
||||
agg = aggregate_class_prototypes(contributions, AggregationMode.SUPPORT_WEIGHTED, beta=1.0)
|
||||
print(f" S_j builder output = {agg}")
|
||||
check("N_ij=0 and missing prototypes are dropped from S_j", agg.get(0) == [1.0])
|
||||
check("a class with no valid contributor is omitted", 1 not in agg)
|
||||
|
||||
dom = normalized_support_weights([1.0, 1000.0], 1.0)
|
||||
print(f" dominance weights [1,1000] at beta=1 = {[round(w, 6) for w in dom]}")
|
||||
check("a single dominant client can dominate the aggregate at beta=1", dom[1] > 0.999)
|
||||
|
||||
rejected = 0
|
||||
for bad in (-0.1, 1.1, None, "x", float("inf")):
|
||||
try:
|
||||
validate_beta(bad)
|
||||
except (ValueError, TypeError):
|
||||
rejected += 1
|
||||
check("invalid beta values are rejected", rejected == 5)
|
||||
|
||||
|
||||
def snapshot_sensitivity(tag: str, path: Path, names: dict) -> None:
|
||||
section(f"B. Direct aggregation effect on a persisted snapshot: {tag}")
|
||||
snap = json.loads(path.read_text())
|
||||
print(f" snapshot: {path.relative_to(ROOT)} (round {snap['round']})")
|
||||
rows = prototype_effect_rows(snap, betas=[0.0, 0.5, 1.0], class_names=names)
|
||||
weights = client_weight_rows(snap, betas=[0.0, 0.25, 0.5, 0.75, 1.0], class_names=names)
|
||||
|
||||
by_class = {}
|
||||
for r in rows:
|
||||
by_class.setdefault(r["class_id"], {})[r["beta"]] = r
|
||||
maxw = {}
|
||||
for w in weights:
|
||||
if w["beta"] == 1.0:
|
||||
cur = maxw.get(w["class_id"])
|
||||
if cur is None or w["weight"] > cur["weight"]:
|
||||
maxw[w["class_id"]] = w
|
||||
|
||||
print(f" {'class':16} {'|S_j|':>5} {'sup_min':>8} {'sup_max':>9} "
|
||||
f"{'disp@0.5':>9} {'disp@1.0':>9} {'maxW@1.0':>9}")
|
||||
for cid in sorted(by_class):
|
||||
r = by_class[cid]
|
||||
n = r[0.0]["n_contributors"]
|
||||
d05 = r[0.5]["displacement_from_beta0"]
|
||||
d10 = r[1.0]["displacement_from_beta0"]
|
||||
mw = maxw.get(cid, {}).get("weight", float("nan"))
|
||||
name = (r[0.0]["class_name"] or cid)
|
||||
print(f" {str(name):16} {n:>5} {r[0.0]['support_min']:>8.1f} "
|
||||
f"{r[0.0]['support_max']:>9.1f} {d05:>9.4f} {d10:>9.4f} {mw:>9.4f}")
|
||||
partial = [cid for cid in by_class if by_class[cid][0.0]["n_contributors"] < 10]
|
||||
full = [cid for cid in by_class if by_class[cid][0.0]["n_contributors"] == 10]
|
||||
if partial:
|
||||
md = sum(by_class[c][1.0]["displacement_from_beta0"] for c in partial) / len(partial)
|
||||
print(f" mean disp@1.0, |S_j|<M classes ({len(partial)}): {md:.4f}")
|
||||
if full:
|
||||
md = sum(by_class[c][1.0]["displacement_from_beta0"] for c in full) / len(full)
|
||||
print(f" mean disp@1.0, |S_j|=M classes ({len(full)}): {md:.4f}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
synthetic_invariants()
|
||||
snapshot_sensitivity(
|
||||
"5G-NIDD, alpha=0.25, seed=0 (beta=0 snapshot)",
|
||||
ANALYSIS / "5gnidd__alpha0.25__seed0__support_weighted__beta0__prototype_snapshot.json",
|
||||
{i: n for i, n in enumerate(
|
||||
["Benign", "HTTPFlood", "ICMPFlood", "SYNFlood", "SYNScan",
|
||||
"SlowrateDoS", "TCPConnectScan", "UDPFlood", "UDPScan"])})
|
||||
snapshot_sensitivity(
|
||||
"X-IIoTID, alpha=0.25, seed=0 (beta=0 snapshot)",
|
||||
ANALYSIS / "xiiotid__alpha0.25__seed0__support_weighted__beta0__prototype_snapshot.json",
|
||||
{i: n for i, n in enumerate(
|
||||
["C&C", "Exfiltration", "Exploitation", "Lateral_movement", "Normal",
|
||||
"RDOS", "Reconnaissance", "Tampering", "Weaponization"])})
|
||||
print("\nREAD-ONLY CHECKS COMPLETE (no files written, no snapshots modified).")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,315 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Post-hoc statistical audit of the completed PROTEAN experiment grid.
|
||||
|
||||
Read-only post-hoc analysis: no training, no partition regeneration, no
|
||||
modification of any existing artifact. Reads the audited comparison tables and
|
||||
per-run metadata under ``results/`` and writes NEW derived tables with unique
|
||||
``posthoc__`` names under ``artifacts/analysis/``.
|
||||
|
||||
Computes:
|
||||
* paired global per-seed differences (original_protean vs selected-beta
|
||||
support_weighted) and condition-level descriptive summaries;
|
||||
* exploratory paired tests (exact sign-flip permutation, exact Wilcoxon
|
||||
signed-rank, paired t 95% CI) with explicit small-n limitations;
|
||||
* validation beta-selection stability (pooled vs per-seed);
|
||||
* per-class and per-client descriptive summaries.
|
||||
|
||||
Run:
|
||||
.venv/bin/python scripts/posthoc_statistical_audit.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import itertools
|
||||
import json
|
||||
import math
|
||||
import statistics
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
ANALYSIS = ROOT / "artifacts" / "analysis"
|
||||
RESULTS = ROOT / "results"
|
||||
|
||||
DATASETS = ["xiiotid", "5gnidd"]
|
||||
ALPHAS = [0.25, 0.50, 0.75]
|
||||
SEEDS = [0, 1, 2]
|
||||
METRICS = ["rare_class_macro_f1", "rare_class_recall", "macro_f1",
|
||||
"weighted_f1", "accuracy"]
|
||||
SELECTED = {("xiiotid", 0.25): 0.0, ("xiiotid", 0.5): 0.75, ("xiiotid", 0.75): 0.5,
|
||||
("5gnidd", 0.25): 0.0, ("5gnidd", 0.5): 1.0, ("5gnidd", 0.75): 0.5}
|
||||
T_ZERO = 1e-6 # numerical "effectively zero" for sign counts
|
||||
T_PRACTICAL = 0.02 # practical negligible band (matches deep comparison)
|
||||
T975_DF2 = 4.302652729 # t_{0.975, df=2}
|
||||
|
||||
|
||||
def read_csv(p: Path) -> list[dict]:
|
||||
with p.open() as fh:
|
||||
return list(csv.DictReader(fh))
|
||||
|
||||
|
||||
def write_csv(name: str, rows: list[dict]) -> None:
|
||||
# Guard: this script may only ever write its own posthoc__ outputs, and may
|
||||
# overwrite them so the analysis is exactly reproducible on rerun. It can
|
||||
# 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()))
|
||||
w.writeheader()
|
||||
w.writerows(rows)
|
||||
print("wrote", path)
|
||||
|
||||
|
||||
def mean(v):
|
||||
return statistics.mean(v)
|
||||
|
||||
|
||||
def std_sample(v):
|
||||
return statistics.stdev(v) if len(v) > 1 else 0.0
|
||||
|
||||
|
||||
def median(v):
|
||||
return statistics.median(v)
|
||||
|
||||
|
||||
# --- exploratory exact tests ------------------------------------------------
|
||||
def signflip_p(deltas):
|
||||
"""Exact two-sided sign-flip permutation test on the mean (n<=~20)."""
|
||||
d = list(deltas)
|
||||
obs = abs(sum(d))
|
||||
if not d or all(x == 0 for x in d):
|
||||
return 1.0
|
||||
total = 0
|
||||
ge = 0
|
||||
for signs in itertools.product((1, -1), repeat=len(d)):
|
||||
s = abs(sum(sign * x for sign, x in zip(signs, d)))
|
||||
total += 1
|
||||
if s >= obs - 1e-12:
|
||||
ge += 1
|
||||
return ge / total
|
||||
|
||||
|
||||
def wilcoxon_exact_p(deltas):
|
||||
"""Exact two-sided Wilcoxon signed-rank (min-rank convention), zeros dropped."""
|
||||
d = [x for x in deltas if abs(x) > T_ZERO]
|
||||
n = len(d)
|
||||
if n == 0:
|
||||
return 1.0
|
||||
order = sorted(range(n), key=lambda i: abs(d[i]))
|
||||
ranks = [0.0] * n
|
||||
i = 0
|
||||
while i < n:
|
||||
j = i
|
||||
while j + 1 < n and abs(d[order[j + 1]]) == abs(d[order[i]]):
|
||||
j += 1
|
||||
avg = (i + j) / 2 + 1
|
||||
for k in range(i, j + 1):
|
||||
ranks[order[k]] = avg
|
||||
i = j + 1
|
||||
w_pos = sum(ranks[i] for i in range(n) if d[i] > 0)
|
||||
w_min_obs = min(w_pos, sum(ranks) - w_pos)
|
||||
dist = defaultdict(int)
|
||||
for signs in itertools.product((1, -1), repeat=n):
|
||||
wp = sum(ranks[i] for i in range(n) if signs[i] > 0)
|
||||
dist[min(wp, sum(ranks) - wp)] += 1
|
||||
le = sum(c for w, c in dist.items() if w <= w_min_obs + 1e-12)
|
||||
return min(1.0, 2 * le / (2 ** n))
|
||||
|
||||
|
||||
def paired_t_ci(deltas):
|
||||
d = list(deltas)
|
||||
n = len(d)
|
||||
m = mean(d)
|
||||
s = std_sample(d)
|
||||
half = T975_DF2 * s / math.sqrt(n) if n > 1 else 0.0
|
||||
return m - half, m + half
|
||||
|
||||
|
||||
# --- pairing verification ---------------------------------------------------
|
||||
def manifests(ds, alpha, seed, beta):
|
||||
o = json.loads((RESULTS / f"{ds}__alpha{alpha:g}__seed{seed}__original_protean"
|
||||
/ "metadata.json").read_text())
|
||||
s = json.loads((RESULTS / f"{ds}__alpha{alpha:g}__seed{seed}__support_weighted__beta{beta:g}"
|
||||
/ "metadata.json").read_text())
|
||||
return o, s
|
||||
|
||||
|
||||
def main() -> None:
|
||||
per_seed = read_csv(ANALYSIS / "deepcmp__global_per_seed.csv")
|
||||
|
||||
# 1. Verify pairing and selected beta, rebuild a per-seed table. ----------
|
||||
rebuilt = []
|
||||
pair_ok = True
|
||||
for ds in DATASETS:
|
||||
for alpha in ALPHAS:
|
||||
beta = SELECTED[(ds, alpha)]
|
||||
for seed in SEEDS:
|
||||
o, s = manifests(ds, alpha, seed, beta)
|
||||
ok = (o["dataset"] == s["dataset"] == ds
|
||||
and abs(float(o["alpha"]) - alpha) < 1e-9
|
||||
and int(o["seed"]) == int(s["seed"]) == seed
|
||||
and o["manifest_content_hash"] == s["manifest_content_hash"]
|
||||
and abs(float(s["beta"]) - beta) < 1e-9)
|
||||
pair_ok = pair_ok and ok
|
||||
for m in METRICS:
|
||||
row = next(r for r in per_seed
|
||||
if r["dataset"] == ds and abs(float(r["alpha"]) - alpha) < 1e-9
|
||||
and int(r["seed"]) == seed and r["metric"] == m)
|
||||
rebuilt.append({
|
||||
"dataset": ds, "alpha": alpha, "seed": seed,
|
||||
"selected_beta": beta, "metric": m,
|
||||
"original": row["original"], "proposed": row["proposed"],
|
||||
"delta": row["delta"],
|
||||
"manifest_content_hash": o["manifest_content_hash"],
|
||||
"pairing_verified": ok})
|
||||
if not pair_ok:
|
||||
raise SystemExit("pairing verification FAILED")
|
||||
print("pairing verified for all 18 condition-seed cells (manifest hash match)")
|
||||
write_csv("posthoc__paired_global_per_seed.csv", rebuilt)
|
||||
|
||||
# 2. Condition-level descriptive summary. -------------------------------
|
||||
by_cond = []
|
||||
tests = []
|
||||
for ds in DATASETS:
|
||||
for alpha in ALPHAS:
|
||||
beta = SELECTED[(ds, alpha)]
|
||||
for m in METRICS:
|
||||
rows = [r for r in rebuilt if r["dataset"] == ds
|
||||
and abs(r["alpha"] - alpha) < 1e-9 and r["metric"] == m]
|
||||
base = [float(r["original"]) for r in rows]
|
||||
prop = [float(r["proposed"]) for r in rows]
|
||||
dlt = [float(r["delta"]) for r in rows]
|
||||
npos = sum(1 for d in dlt if d > T_ZERO)
|
||||
nneg = sum(1 for d in dlt if d < -T_ZERO)
|
||||
nzero = sum(1 for d in dlt if abs(d) <= T_ZERO)
|
||||
by_cond.append({
|
||||
"dataset": ds, "alpha": alpha, "selected_beta": beta, "metric": m,
|
||||
"original_seed0": base[0], "original_seed1": base[1], "original_seed2": base[2],
|
||||
"proposed_seed0": prop[0], "proposed_seed1": prop[1], "proposed_seed2": prop[2],
|
||||
"delta_seed0": dlt[0], "delta_seed1": dlt[1], "delta_seed2": dlt[2],
|
||||
"delta_mean": mean(dlt), "delta_std_sample": std_sample(dlt),
|
||||
"delta_median": median(dlt), "delta_min": min(dlt), "delta_max": max(dlt),
|
||||
"baseline_std_sample": std_sample(base),
|
||||
"proposed_std_sample": std_sample(prop),
|
||||
"n_pos": npos, "n_neg": nneg, "n_zero": nzero,
|
||||
"same_sign_all_seeds": (npos == 3 or nneg == 3)})
|
||||
lo, hi = paired_t_ci(dlt)
|
||||
tests.append({
|
||||
"dataset": ds, "alpha": alpha, "selected_beta": beta, "metric": m,
|
||||
"n_pairs": len(dlt),
|
||||
"deltas": "|".join(f"{d:.6f}" for d in dlt),
|
||||
"signflip_exact_p_two_sided": signflip_p(dlt),
|
||||
"wilcoxon_exact_p_two_sided": wilcoxon_exact_p(dlt),
|
||||
"paired_t_ci95_low": lo, "paired_t_ci95_high": hi,
|
||||
"min_attainable_signflip_p": 2 / (2 ** len(dlt)),
|
||||
"note": ("exploratory; 3 seeds; no inferential power; "
|
||||
"beta=0 conditions are numerical, not a treatment contrast")})
|
||||
write_csv("posthoc__paired_global_by_condition.csv", by_cond)
|
||||
write_csv("posthoc__paired_test_results.csv", tests)
|
||||
|
||||
# 3. Beta-selection stability. -----------------------------------------
|
||||
stability = []
|
||||
for ds in DATASETS:
|
||||
for alpha in ALPHAS:
|
||||
vs = read_csv(ANALYSIS / f"{ds}__alpha{alpha:g}__multiseed__validation_per_seed.csv")
|
||||
scores = defaultdict(dict) # seed -> beta -> score
|
||||
for r in vs:
|
||||
scores[int(r["seed"])][float(r["beta"])] = float(r["val_rare_macro_f1_per_client_mean"])
|
||||
per_seed_beta = {s: max(scores[s], key=lambda b: (scores[s][b], -b)) for s in scores}
|
||||
pooled = {b: mean([scores[s][b] for s in SEEDS]) for b in sorted(next(iter(scores.values())))}
|
||||
pooled_beta = max(pooled, key=lambda b: (pooled[b], -b))
|
||||
ordered = sorted(pooled.values(), reverse=True)
|
||||
agree = sum(1 for s in SEEDS if abs(per_seed_beta[s] - pooled_beta) < 1e-9)
|
||||
second_beta = sorted((b for b in pooled if abs(b - pooled_beta) > 1e-9),
|
||||
key=lambda b: -pooled[b])[0]
|
||||
stability.append({
|
||||
"dataset": ds, "alpha": alpha,
|
||||
"pooled_selected_beta": pooled_beta,
|
||||
"per_seed_beta_s0": per_seed_beta[0],
|
||||
"per_seed_beta_s1": per_seed_beta[1],
|
||||
"per_seed_beta_s2": per_seed_beta[2],
|
||||
"n_seeds_agree_pooled": agree,
|
||||
"pooled_score_selected": pooled[pooled_beta],
|
||||
"second_best_beta": second_beta,
|
||||
"second_best_score": pooled[second_beta],
|
||||
"margin_best_minus_second": pooled[pooled_beta] - pooled[second_beta],
|
||||
"candidate_score_range": ordered[0] - ordered[-1],
|
||||
"test_used_for_selection": False})
|
||||
write_csv("posthoc__selection_stability.csv", stability)
|
||||
|
||||
# 4. Per-class summary. --------------------------------------------------
|
||||
pc = read_csv(ANALYSIS / "deepcmp__per_class.csv")
|
||||
grp = defaultdict(list)
|
||||
for r in pc:
|
||||
grp[(r["dataset"], r["class_name"])].append(float(r["delta_f1"]))
|
||||
per_class = []
|
||||
for (ds, name), vals in sorted(grp.items(), key=lambda kv: -mean(kv[1])):
|
||||
per_class.append({
|
||||
"dataset": ds, "class_name": name, "n_obs": len(vals),
|
||||
"mean_delta_f1": mean(vals), "median_delta_f1": median(vals),
|
||||
"min_delta_f1": min(vals), "max_delta_f1": max(vals),
|
||||
"n_positive": sum(1 for v in vals if v > 0),
|
||||
"n_negative": sum(1 for v in vals if v < 0)})
|
||||
write_csv("posthoc__per_class_summary.csv", per_class)
|
||||
|
||||
# 5. Per-client summary (descriptive only). ------------------------------
|
||||
cl = read_csv(ANALYSIS / "deepcmp__per_client.csv")
|
||||
by_condition = defaultdict(list)
|
||||
for r in cl:
|
||||
by_condition[(r["dataset"], float(r["alpha"]))].append(r)
|
||||
per_client = []
|
||||
for (ds, alpha), rows in sorted(by_condition.items()):
|
||||
d = [float(r["delta_rare_f1"]) for r in rows]
|
||||
per_client.append({
|
||||
"dataset": ds, "alpha": alpha, "selected_beta": SELECTED[(ds, alpha)],
|
||||
"n_client_seed_obs": len(d),
|
||||
"n_improved_gt_0.02": sum(1 for x in d if x > T_PRACTICAL),
|
||||
"n_degraded_lt_-0.02": sum(1 for x in d if x < -T_PRACTICAL),
|
||||
"n_unchanged": sum(1 for x in d if abs(x) <= T_PRACTICAL),
|
||||
"mean_delta": mean(d), "median_delta": median(d),
|
||||
"min_delta": min(d), "max_delta": max(d),
|
||||
"std_sample_within_condition": std_sample(d)})
|
||||
write_csv("posthoc__per_client_summary.csv", per_client)
|
||||
|
||||
# --- console summary ----------------------------------------------------
|
||||
print("\n=== paired rare-class macro-F1 (delta = proposed - original) ===")
|
||||
for r in by_cond:
|
||||
if r["metric"] != "rare_class_macro_f1":
|
||||
continue
|
||||
print(f" {r['dataset']:8} a{r['alpha']:<4} beta={r['selected_beta']:<4} "
|
||||
f"mean={float(r['delta_mean']):+.4f} std={float(r['delta_std_sample']):.4f} "
|
||||
f"base_std={float(r['baseline_std_sample']):.4f} prop_std={float(r['proposed_std_sample']):.4f} "
|
||||
f"pos/neg/zero={r['n_pos']}/{r['n_neg']}/{r['n_zero']} same_sign={r['same_sign_all_seeds']}")
|
||||
print("\n=== exact tests (rare-class macro-F1) ===")
|
||||
for r in tests:
|
||||
if r["metric"] != "rare_class_macro_f1":
|
||||
continue
|
||||
print(f" {r['dataset']:8} a{r['alpha']:<4} beta={r['selected_beta']:<4} "
|
||||
f"signflip_p={r['signflip_exact_p_two_sided']:.4f} "
|
||||
f"wilcoxon_p={r['wilcoxon_exact_p_two_sided']:.4f} "
|
||||
f"tCI=[{r['paired_t_ci95_low']:+.4f},{r['paired_t_ci95_high']:+.4f}] "
|
||||
f"(min signflip p={r['min_attainable_signflip_p']:.4f})")
|
||||
print("\n=== selection stability ===")
|
||||
for r in stability:
|
||||
print(f" {r['dataset']:8} a{r['alpha']:<4} pooled={r['pooled_selected_beta']:<4} "
|
||||
f"per-seed={r['per_seed_beta_s0']}/{r['per_seed_beta_s1']}/{r['per_seed_beta_s2']} "
|
||||
f"agree={r['n_seeds_agree_pooled']}/3 margin={float(r['margin_best_minus_second']):.4f} "
|
||||
f"range={float(r['candidate_score_range']):.4f}")
|
||||
print("\n=== S_j audit ===")
|
||||
sj = read_csv(ANALYSIS / "sj_participant_rule_analysis.csv")
|
||||
lt = sum(1 for r in sj if int(r["S_j"]) < int(r["M"]))
|
||||
print(f" |S_j| < M cells: {lt} / {len(sj)}")
|
||||
print("\n=== per-class extremes (mean delta F1) ===")
|
||||
print(" top +:", ", ".join(f"{r['dataset']}/{r['class_name']} {float(r['mean_delta_f1']):+.4f}"
|
||||
for r in per_class[:4]))
|
||||
print(" top -:", ", ".join(f"{r['dataset']}/{r['class_name']} {float(r['mean_delta_f1']):+.4f}"
|
||||
for r in per_class[-4:]))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,99 @@
|
||||
# Sweep analysis scripts
|
||||
|
||||
Read-only analysis helpers for the completed seed-0 sweeps. They were originally
|
||||
written inside `results/sweep/` and `results/sweep_repro/` (both git-ignored);
|
||||
these copies are the version-controlled source.
|
||||
|
||||
All four scripts accept `--repo-root` (default: the repository that contains
|
||||
`scripts/sweep/`, i.e. two levels up from the script). Data is read from the
|
||||
sweep run directories and, where noted, from the earlier grid runs and
|
||||
`artifacts/analysis/`. Nothing is retrained.
|
||||
|
||||
## `analyze_sweep.py`
|
||||
|
||||
Inputs
|
||||
- `results/sweep/runs/<dataset>__alpha<alpha>__seed0__support_weighted__beta<beta>/COMPLETE`
|
||||
- `.../results/<run>/val_selection.json`
|
||||
- `.../results/<run>/test_global_metrics.json`
|
||||
- `results/<run>/val_selection.json` and `test_global_metrics.json` for the earlier
|
||||
grid runs (stage 3)
|
||||
|
||||
Outputs
|
||||
- `results/sweep/analysis/selection.csv` (validation only)
|
||||
- `results/sweep/analysis/test_at_selected_beta.csv`
|
||||
- `results/sweep/analysis/repro_vs_previous.csv`
|
||||
|
||||
Command
|
||||
```bash
|
||||
python3 scripts/sweep/analyze_sweep.py
|
||||
# or, against a different tree:
|
||||
python3 scripts/sweep/analyze_sweep.py --repo-root /path/to/repo
|
||||
```
|
||||
|
||||
## `check_noise.py`
|
||||
|
||||
Inputs
|
||||
- `results/sweep/runs/<run>/results/<run>/{history.json,val_selection.json,test_global_metrics.json}`
|
||||
- `results/<run>/{history.json,val_selection.json,test_global_metrics.json}` (earlier grid)
|
||||
|
||||
Outputs
|
||||
- `results/sweep/analysis/noise_checks.json`
|
||||
|
||||
Command
|
||||
```bash
|
||||
python3 scripts/sweep/check_noise.py
|
||||
# or:
|
||||
python3 scripts/sweep/check_noise.py --repo-root /path/to/repo
|
||||
```
|
||||
|
||||
## `compare_with_grid.py`
|
||||
|
||||
Inputs
|
||||
- `results/sweep/analysis/selection.csv` (run `analyze_sweep.py` first)
|
||||
- `artifacts/analysis/final__six_condition_master.csv`
|
||||
- `artifacts/analysis/<dataset>__alpha<alpha>__multiseed__validation_per_seed.csv`
|
||||
|
||||
Outputs
|
||||
- `results/sweep/analysis/compare_with_grid.csv`
|
||||
|
||||
Command
|
||||
```bash
|
||||
python3 scripts/sweep/compare_with_grid.py
|
||||
# or:
|
||||
python3 scripts/sweep/compare_with_grid.py --repo-root /path/to/repo
|
||||
```
|
||||
|
||||
## `compare_repro.py`
|
||||
|
||||
Inputs
|
||||
- `results/sweep_repro/a_1thread_repeat/results/<run>/`
|
||||
- `results/sweep_repro/b_8thread/results/<run>/`
|
||||
- `results/sweep/runs/<run>/results/<run>/`
|
||||
- `results/<run>/` (earlier grid)
|
||||
- prototype snapshots under `results/sweep_repro/*/analysis/`,
|
||||
`results/sweep/runs/<run>/analysis/` and `artifacts/analysis/`
|
||||
|
||||
where `<run>` is `xiiotid__alpha0.25__seed0__support_weighted__beta0`.
|
||||
|
||||
Outputs
|
||||
- `results/sweep_repro/compare_repro.json`
|
||||
- a compact comparison table on stdout
|
||||
|
||||
Command
|
||||
```bash
|
||||
python3 scripts/sweep/compare_repro.py
|
||||
# or:
|
||||
python3 scripts/sweep/compare_repro.py --repo-root /path/to/repo
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `results/` is git-ignored. These scripts write only into
|
||||
`results/sweep/analysis/` and `results/sweep_repro/`; they never write into a
|
||||
tracked file.
|
||||
- `analyze_sweep.py` opens validation data in stage 1 and only opens test data
|
||||
afterwards, by construction. The scripts do not select or recommend a beta for
|
||||
the thesis; they print descriptive tables.
|
||||
- The computation is unchanged from the originals. The only change is that the
|
||||
repository root is a `--repo-root` argument with a relative default instead of
|
||||
being derived from the script's old location inside `results/`.
|
||||
@@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Read-only analysis of the 30-run 1-thread sweep (seed 0).
|
||||
|
||||
Stage 1 (validation only) -> selection.csv
|
||||
For each (dataset, alpha) choose the beta with the highest
|
||||
val_rare_class_macro_f1_per_client_mean. Ties go to the smaller beta.
|
||||
No test file is opened in this stage.
|
||||
|
||||
Stage 2 (test, read only AFTER stage 1 is written) -> test_at_selected_beta.csv
|
||||
Test rare-class macro-F1 at the beta fixed in stage 1, next to every other
|
||||
candidate, for description only.
|
||||
|
||||
Stage 3 (reproducibility vs. the earlier 108-run grid, seed 0) -> repro_vs_previous.csv
|
||||
Same (dataset, alpha, seed 0, beta) re-run with 1 thread vs. the earlier
|
||||
run in results/<name>. Reports absolute differences; it does not select
|
||||
anything.
|
||||
|
||||
Nothing under planningawal/ or results/<old runs> is written.
|
||||
|
||||
Inputs and outputs are rooted at --repo-root, which defaults to the repository
|
||||
that contains this script (scripts/sweep/ -> repo root). No computation
|
||||
depends on the root.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
DEFAULT_REPO = SCRIPT_DIR.parents[1]
|
||||
|
||||
REPO = DEFAULT_REPO
|
||||
SWEEP = REPO / "results" / "sweep"
|
||||
RUNS = SWEEP / "runs"
|
||||
PREV = REPO / "results"
|
||||
OUT = SWEEP / "analysis"
|
||||
|
||||
|
||||
def configure(repo_root: Path) -> None:
|
||||
"""Rebind the path globals for an explicit repository root."""
|
||||
global REPO, SWEEP, RUNS, PREV, OUT
|
||||
REPO = repo_root.resolve()
|
||||
SWEEP = REPO / "results" / "sweep"
|
||||
RUNS = SWEEP / "runs"
|
||||
PREV = REPO / "results"
|
||||
OUT = SWEEP / "analysis"
|
||||
|
||||
DATASETS = ("xiiotid", "5gnidd")
|
||||
ALPHAS = ("0.25", "0.5", "0.75")
|
||||
BETAS = ("0", "0.25", "0.5", "0.75", "1")
|
||||
SEL_KEY = "val_rare_class_macro_f1_per_client_mean"
|
||||
|
||||
|
||||
def name(ds: str, a: str, b: str) -> str:
|
||||
return f"{ds}__alpha{a}__seed0__support_weighted__beta{b}"
|
||||
|
||||
|
||||
def rdir(root: Path, ds: str, a: str, b: str) -> Path:
|
||||
n = name(ds, a, b)
|
||||
return root / n / "results" / n if root == RUNS else root / n
|
||||
|
||||
|
||||
def load(path: Path) -> dict:
|
||||
with path.open(encoding="utf-8") as h:
|
||||
return json.load(h)
|
||||
|
||||
|
||||
def write_csv(path: Path, rows: list[dict]) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with path.open("w", newline="", encoding="utf-8") as h:
|
||||
w = csv.DictWriter(h, fieldnames=list(rows[0]))
|
||||
w.writeheader()
|
||||
w.writerows(rows)
|
||||
|
||||
|
||||
def stage1() -> list[dict]:
|
||||
rows = []
|
||||
for ds in DATASETS:
|
||||
for a in ALPHAS:
|
||||
cand = []
|
||||
for b in BETAS:
|
||||
d = rdir(RUNS, ds, a, b)
|
||||
if not (RUNS / name(ds, a, b) / "COMPLETE").is_file():
|
||||
sys.exit(f"missing COMPLETE: {name(ds, a, b)}")
|
||||
sel = load(d / "val_selection.json")
|
||||
assert sel["selection_split"] == "validation"
|
||||
assert sel["test_used_for_selection"] is False
|
||||
cand.append((float(sel[SEL_KEY]), -float(b), b, sel))
|
||||
best = max(cand, key=lambda t: (t[0], t[1]))
|
||||
ordered = sorted(cand, key=lambda t: -t[0])
|
||||
gap = ordered[0][0] - ordered[1][0]
|
||||
for v, _, b, sel in cand:
|
||||
rows.append(
|
||||
{
|
||||
"dataset": ds,
|
||||
"alpha": a,
|
||||
"beta": b,
|
||||
"val_rare_f1_per_client_mean": f"{v:.9f}",
|
||||
"val_rare_f1_global": f"{sel['val_rare_class_macro_f1_global']:.9f}",
|
||||
"val_rare_recall_per_client_mean": f"{sel['val_rare_class_recall_per_client_mean']:.9f}",
|
||||
"val_macro_f1_global": f"{sel['val_macro_f1_global']:.9f}",
|
||||
"selected": int(b == best[2]),
|
||||
"margin_to_runner_up": f"{gap:.9f}" if b == best[2] else "",
|
||||
}
|
||||
)
|
||||
return rows
|
||||
|
||||
|
||||
def stage2(sel_rows: list[dict]) -> list[dict]:
|
||||
chosen = {(r["dataset"], r["alpha"]): r["beta"] for r in sel_rows if r["selected"]}
|
||||
rows = []
|
||||
for ds in DATASETS:
|
||||
for a in ALPHAS:
|
||||
for b in BETAS:
|
||||
t = load(rdir(RUNS, ds, a, b) / "test_global_metrics.json")
|
||||
rows.append(
|
||||
{
|
||||
"dataset": ds,
|
||||
"alpha": a,
|
||||
"beta": b,
|
||||
"selected_on_validation": int(chosen[(ds, a)] == b),
|
||||
"test_rare_f1_global": f"{t['rare_class_macro_f1']:.9f}",
|
||||
"test_rare_recall_global": f"{t['rare_class_recall']:.9f}",
|
||||
"test_macro_f1": f"{t['macro_f1']:.9f}",
|
||||
"test_accuracy": f"{t['accuracy']:.9f}",
|
||||
"test_rare_support": t["rare_support"],
|
||||
}
|
||||
)
|
||||
return rows
|
||||
|
||||
|
||||
def stage3() -> list[dict]:
|
||||
rows = []
|
||||
for ds in DATASETS:
|
||||
for a in ALPHAS:
|
||||
for b in BETAS:
|
||||
new = rdir(RUNS, ds, a, b)
|
||||
old = rdir(PREV, ds, a, b)
|
||||
if not old.is_dir():
|
||||
rows.append({"dataset": ds, "alpha": a, "beta": b, "note": "no previous run"})
|
||||
continue
|
||||
nt = load(new / "test_global_metrics.json")
|
||||
ot = load(old / "test_global_metrics.json")
|
||||
row = {
|
||||
"dataset": ds,
|
||||
"alpha": a,
|
||||
"beta": b,
|
||||
"test_rare_f1_new": f"{nt['rare_class_macro_f1']:.9f}",
|
||||
"test_rare_f1_prev": f"{ot['rare_class_macro_f1']:.9f}",
|
||||
"abs_diff_test_rare_f1": f"{abs(nt['rare_class_macro_f1'] - ot['rare_class_macro_f1']):.3e}",
|
||||
"abs_diff_test_macro_f1": f"{abs(nt['macro_f1'] - ot['macro_f1']):.3e}",
|
||||
"abs_diff_test_accuracy": f"{abs(nt['accuracy'] - ot['accuracy']):.3e}",
|
||||
"note": "",
|
||||
}
|
||||
nv, ov = new / "val_selection.json", old / "val_selection.json"
|
||||
if nv.is_file() and ov.is_file():
|
||||
row["abs_diff_val_sel_metric"] = (
|
||||
f"{abs(load(nv)[SEL_KEY] - load(ov)[SEL_KEY]):.3e}"
|
||||
)
|
||||
else:
|
||||
row["abs_diff_val_sel_metric"] = ""
|
||||
row["note"] = "previous run has no val_selection.json"
|
||||
rows.append(row)
|
||||
return rows
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--repo-root",
|
||||
type=Path,
|
||||
default=DEFAULT_REPO,
|
||||
help="repository root containing results/ (default: %(default)s)",
|
||||
)
|
||||
args = parser.parse_args(argv)
|
||||
configure(args.repo_root)
|
||||
|
||||
s1 = stage1()
|
||||
write_csv(OUT / "selection.csv", s1)
|
||||
print(f"stage 1 written: {OUT / 'selection.csv'} ({len(s1)} rows); test not opened so far")
|
||||
s2 = stage2(s1)
|
||||
write_csv(OUT / "test_at_selected_beta.csv", s2)
|
||||
s3 = stage3()
|
||||
write_csv(OUT / "repro_vs_previous.csv", s3)
|
||||
print(f"stage 2/3 written under {OUT}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Read-only checks on the sweep (1 thread) vs. the earlier grid (seed 0).
|
||||
|
||||
Three questions, no training:
|
||||
A. Where do paired runs first diverge (round-0 vs later rounds)?
|
||||
B. Is the sweep-minus-grid difference systematic (sign) or scattered?
|
||||
C. How stable is the beta ranking, per condition, between the two runs?
|
||||
|
||||
Writes results/sweep/analysis/noise_checks.json. Exploratory only: the 30
|
||||
pairs share partitions across betas, so they are NOT independent; the sign
|
||||
statistics are descriptive, not significance claims.
|
||||
|
||||
Paths are rooted at --repo-root, which defaults to the repository that contains
|
||||
this script (scripts/sweep/ -> repo root). No computation depends on the root.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import json
|
||||
import math
|
||||
from pathlib import Path
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
DEFAULT_REPO = SCRIPT_DIR.parents[1]
|
||||
|
||||
REPO = DEFAULT_REPO
|
||||
SWEEP = REPO / "results" / "sweep"
|
||||
RUNS = SWEEP / "runs"
|
||||
PREV = REPO / "results"
|
||||
OUT = SWEEP / "analysis" / "noise_checks.json"
|
||||
|
||||
|
||||
def configure(repo_root: Path) -> None:
|
||||
"""Rebind the path globals for an explicit repository root."""
|
||||
global REPO, SWEEP, RUNS, PREV, OUT
|
||||
REPO = repo_root.resolve()
|
||||
SWEEP = REPO / "results" / "sweep"
|
||||
RUNS = SWEEP / "runs"
|
||||
PREV = REPO / "results"
|
||||
OUT = SWEEP / "analysis" / "noise_checks.json"
|
||||
|
||||
DATASETS = ("xiiotid", "5gnidd")
|
||||
ALPHAS = ("0.25", "0.5", "0.75")
|
||||
BETAS = ("0", "0.25", "0.5", "0.75", "1")
|
||||
SEL = "val_rare_class_macro_f1_per_client_mean"
|
||||
|
||||
|
||||
def name(ds, a, b):
|
||||
return f"{ds}__alpha{a}__seed0__support_weighted__beta{b}"
|
||||
|
||||
|
||||
def new_dir(ds, a, b):
|
||||
n = name(ds, a, b)
|
||||
return RUNS / n / "results" / n
|
||||
|
||||
|
||||
def old_dir(ds, a, b):
|
||||
return PREV / name(ds, a, b)
|
||||
|
||||
|
||||
def jl(p):
|
||||
with p.open(encoding="utf-8") as h:
|
||||
return json.load(h)
|
||||
|
||||
|
||||
def spearman(x, y):
|
||||
def ranks(v):
|
||||
order = sorted(range(len(v)), key=lambda i: v[i])
|
||||
r = [0.0] * len(v)
|
||||
i = 0
|
||||
while i < len(order):
|
||||
j = i
|
||||
while j + 1 < len(order) and v[order[j + 1]] == v[order[i]]:
|
||||
j += 1
|
||||
for k in range(i, j + 1):
|
||||
r[order[k]] = (i + j) / 2 + 1
|
||||
i = j + 1
|
||||
return r
|
||||
|
||||
rx, ry = ranks(x), ranks(y)
|
||||
mx, my = sum(rx) / len(rx), sum(ry) / len(ry)
|
||||
num = sum((a - mx) * (b - my) for a, b in zip(rx, ry))
|
||||
den = math.sqrt(sum((a - mx) ** 2 for a in rx) * sum((b - my) ** 2 for b in ry))
|
||||
return num / den if den else float("nan")
|
||||
|
||||
|
||||
def binom_two_sided(k, n):
|
||||
"""Exact two-sided sign-test p, p0 = 0.5."""
|
||||
tail = sum(math.comb(n, i) for i in range(0, min(k, n - k) + 1)) / 2**n
|
||||
return min(1.0, 2 * tail)
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--repo-root",
|
||||
type=Path,
|
||||
default=DEFAULT_REPO,
|
||||
help="repository root containing results/ (default: %(default)s)",
|
||||
)
|
||||
args = parser.parse_args(argv)
|
||||
configure(args.repo_root)
|
||||
|
||||
res: dict = {"A_divergence": [], "B_sign": {}, "C_rank": []}
|
||||
|
||||
# A. per-round divergence (history.json: one dict per round)
|
||||
first_round_counts: dict = {}
|
||||
for ds in DATASETS:
|
||||
for a in ALPHAS:
|
||||
for b in BETAS:
|
||||
hn, ho = jl(new_dir(ds, a, b) / "history.json"), jl(old_dir(ds, a, b) / "history.json")
|
||||
diffs = [
|
||||
abs(x["rare_class_macro_f1"] - y["rare_class_macro_f1"])
|
||||
for x, y in zip(hn, ho)
|
||||
]
|
||||
first = next((i for i, d in enumerate(diffs) if d > 0), None)
|
||||
first_round_counts[str(first)] = first_round_counts.get(str(first), 0) + 1
|
||||
res["A_divergence"].append(
|
||||
{"dataset": ds, "alpha": a, "beta": b, "first_round_with_difference": first,
|
||||
"round0_abs_diff_rare_f1": diffs[0], "last_round_abs_diff_rare_f1": diffs[-1],
|
||||
"n_samples_equal_all_rounds": all(x["n_samples"] == y["n_samples"] for x, y in zip(hn, ho))}
|
||||
)
|
||||
res["A_summary"] = {"first_round_with_difference_counts": first_round_counts}
|
||||
|
||||
# B. signed differences (sweep - grid)
|
||||
for key, fname, field in (
|
||||
("test_rare_f1", "test_global_metrics.json", "rare_class_macro_f1"),
|
||||
("val_selection_metric", "val_selection.json", SEL),
|
||||
):
|
||||
d = []
|
||||
for ds in DATASETS:
|
||||
for a in ALPHAS:
|
||||
for b in BETAS:
|
||||
d.append(jl(new_dir(ds, a, b) / fname)[field] - jl(old_dir(ds, a, b) / fname)[field])
|
||||
pos = sum(1 for v in d if v > 0)
|
||||
neg = sum(1 for v in d if v < 0)
|
||||
res["B_sign"][key] = {
|
||||
"n": len(d), "n_sweep_higher": pos, "n_sweep_lower": neg,
|
||||
"mean_signed_diff": sum(d) / len(d),
|
||||
"mean_abs_diff": sum(abs(v) for v in d) / len(d),
|
||||
"sign_test_two_sided_p_NOT_independent_pairs": binom_two_sided(min(pos, neg), pos + neg),
|
||||
}
|
||||
by_ds = {}
|
||||
for ds in DATASETS:
|
||||
sub = [v for i, v in enumerate(d) if i // 15 == DATASETS.index(ds)]
|
||||
by_ds[ds] = {"mean_signed": sum(sub) / len(sub), "mean_abs": sum(abs(v) for v in sub) / len(sub)}
|
||||
res["B_sign"][key]["by_dataset"] = by_ds
|
||||
|
||||
# C. ranking stability
|
||||
for ds in DATASETS:
|
||||
for a in ALPHAS:
|
||||
s = [jl(new_dir(ds, a, b) / "val_selection.json")[SEL] for b in BETAS]
|
||||
o = [jl(old_dir(ds, a, b) / "val_selection.json")[SEL] for b in BETAS]
|
||||
mad = max(abs(x - y) for x, y in zip(s, o))
|
||||
best_s = max(s)
|
||||
close = [BETAS[i] for i, v in enumerate(s) if best_s - v <= mad]
|
||||
res["C_rank"].append(
|
||||
{"dataset": ds, "alpha": a, "spearman_sweep_vs_grid_over_5_betas": spearman(s, o),
|
||||
"max_abs_val_diff": mad,
|
||||
"betas_within_max_diff_of_sweep_best": close}
|
||||
)
|
||||
|
||||
OUT.parent.mkdir(parents=True, exist_ok=True)
|
||||
with OUT.open("w", encoding="utf-8") as h:
|
||||
json.dump(res, h, indent=2)
|
||||
print(f"written {OUT}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compare the two repro runs (xiiotid alpha0.25 seed0 beta0) with the sweep run and the old grid run.
|
||||
|
||||
Read-only. Writes results/sweep_repro/compare_repro.json and prints a compact table.
|
||||
|
||||
Paths are rooted at --repo-root, which defaults to the repository that contains
|
||||
this script (scripts/sweep/ -> repo root). No computation depends on the root.
|
||||
|
||||
Pairs:
|
||||
A_vs_sweep : a_1thread_repeat vs results/sweep run (same 1-thread setup)
|
||||
B_vs_grid : b_8thread vs results/<old grid run>
|
||||
A_vs_grid, B_vs_sweep, sweep_vs_grid : context
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
DEFAULT_REPO = SCRIPT_DIR.parents[1]
|
||||
N = "xiiotid__alpha0.25__seed0__support_weighted__beta0"
|
||||
JSON_FILES = ("history.json", "test_global_metrics.json", "val_global_metrics.json", "val_selection.json")
|
||||
SEL = "val_rare_class_macro_f1_per_client_mean"
|
||||
|
||||
REPO = DEFAULT_REPO
|
||||
DIRS: dict[str, Path] = {}
|
||||
SNAP: dict[str, Path] = {}
|
||||
OUT = REPO / "results" / "sweep_repro" / "compare_repro.json"
|
||||
|
||||
|
||||
def configure(repo_root: Path) -> None:
|
||||
"""Rebind the path globals for an explicit repository root."""
|
||||
global REPO, DIRS, SNAP, OUT
|
||||
REPO = repo_root.resolve()
|
||||
DIRS = {
|
||||
"a_1thread_repeat": REPO / "results/sweep_repro/a_1thread_repeat/results" / N,
|
||||
"b_8thread": REPO / "results/sweep_repro/b_8thread/results" / N,
|
||||
"sweep": REPO / "results/sweep/runs" / N / "results" / N,
|
||||
"grid": REPO / "results" / N,
|
||||
}
|
||||
SNAP = {
|
||||
"a_1thread_repeat": REPO / "results/sweep_repro/a_1thread_repeat/analysis" / f"{N}__prototype_snapshot.json",
|
||||
"b_8thread": REPO / "results/sweep_repro/b_8thread/analysis" / f"{N}__prototype_snapshot.json",
|
||||
"sweep": REPO / "results/sweep/runs" / N / "analysis" / f"{N}__prototype_snapshot.json",
|
||||
"grid": REPO / "artifacts/analysis" / f"{N}__prototype_snapshot.json",
|
||||
}
|
||||
OUT = REPO / "results" / "sweep_repro" / "compare_repro.json"
|
||||
|
||||
|
||||
configure(DEFAULT_REPO)
|
||||
|
||||
|
||||
def jl(p: Path):
|
||||
with p.open(encoding="utf-8") as h:
|
||||
return json.load(h)
|
||||
|
||||
|
||||
def sha(p: Path) -> str:
|
||||
return hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def compare(x: str, y: str) -> dict:
|
||||
out: dict = {}
|
||||
for f in JSON_FILES:
|
||||
px, py = DIRS[x] / f, DIRS[y] / f
|
||||
if not (px.is_file() and py.is_file()):
|
||||
out[f] = "missing in " + ("x" if not px.is_file() else "y")
|
||||
continue
|
||||
out[f] = {"byte_identical": sha(px) == sha(py), "json_equal": jl(px) == jl(py)}
|
||||
hx, hy = jl(DIRS[x] / "history.json"), jl(DIRS[y] / "history.json")
|
||||
d = [abs(a["rare_class_macro_f1"] - b["rare_class_macro_f1"]) for a, b in zip(hx, hy)]
|
||||
out["history_rare_f1_abs_diff_by_round"] = d
|
||||
tx, ty = jl(DIRS[x] / "test_global_metrics.json"), jl(DIRS[y] / "test_global_metrics.json")
|
||||
out["test_rare_f1"] = {x: tx["rare_class_macro_f1"], y: ty["rare_class_macro_f1"],
|
||||
"abs_diff": abs(tx["rare_class_macro_f1"] - ty["rare_class_macro_f1"])}
|
||||
vx, vy = jl(DIRS[x] / "val_selection.json"), jl(DIRS[y] / "val_selection.json")
|
||||
out["val_selection_metric"] = {x: vx[SEL], y: vy[SEL], "abs_diff": abs(vx[SEL] - vy[SEL])}
|
||||
sx, sy = SNAP[x], SNAP[y]
|
||||
if sx.is_file() and sy.is_file():
|
||||
out["prototype_snapshot"] = {"byte_identical": sha(sx) == sha(sy), "json_equal": jl(sx) == jl(sy)}
|
||||
else:
|
||||
out["prototype_snapshot"] = "missing"
|
||||
return out
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--repo-root",
|
||||
type=Path,
|
||||
default=DEFAULT_REPO,
|
||||
help="repository root containing results/ and artifacts/ (default: %(default)s)",
|
||||
)
|
||||
args = parser.parse_args(argv)
|
||||
configure(args.repo_root)
|
||||
|
||||
pairs = [("a_1thread_repeat", "sweep"), ("b_8thread", "grid"), ("a_1thread_repeat", "grid"),
|
||||
("b_8thread", "sweep"), ("sweep", "grid"), ("a_1thread_repeat", "b_8thread")]
|
||||
res = {f"{x}__vs__{y}": compare(x, y) for x, y in pairs}
|
||||
out = OUT
|
||||
out.write_text(json.dumps(res, indent=2), encoding="utf-8")
|
||||
for k, v in res.items():
|
||||
t = v["test_rare_f1"]["abs_diff"]
|
||||
s = v["val_selection_metric"]["abs_diff"]
|
||||
h = v["history_rare_f1_abs_diff_by_round"]
|
||||
same = {f: v[f]["json_equal"] for f in JSON_FILES if isinstance(v[f], dict)}
|
||||
snap = v["prototype_snapshot"]
|
||||
snap_s = snap["byte_identical"] if isinstance(snap, dict) else snap
|
||||
print(f"{k:34s} test_rare={t:.3e} val_sel={s:.3e} round0={h[0]:.3e} last={h[-1]:.3e} "
|
||||
f"all_json_equal={all(same.values())} snapshot_identical={snap_s}")
|
||||
print(f"written {out}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compare the 1-thread seed-0 validation selection with the earlier 108-run grid.
|
||||
|
||||
Read-only. Uses VALIDATION metrics and the already-fixed pooled beta only;
|
||||
no test file is opened.
|
||||
|
||||
Columns written to analysis/compare_with_grid.csv, per (dataset, alpha):
|
||||
beta_sweep_seed0 beta chosen from results/sweep (1 thread, seed 0)
|
||||
beta_grid_seed0 beta chosen from the earlier grid, seed 0 only (per-seed diagnostic)
|
||||
beta_grid_pooled PRIMARY pooled-validation beta of the earlier grid (3 seeds)
|
||||
sweep_equals_grid_s0 whether the two seed-0 choices coincide
|
||||
grid_s0_margin top-1 minus top-2 validation score of the earlier seed-0 run
|
||||
sweep_margin same for the sweep
|
||||
max_abs_val_diff_s0 largest |sweep - grid| validation difference over the 5 betas
|
||||
sweep_pick_rank_in_grid_s0 rank (1 = best) the sweep's beta has in the grid's seed-0 ranking
|
||||
|
||||
Paths are rooted at --repo-root, which defaults to the repository that contains
|
||||
this script (scripts/sweep/ -> repo root). No computation depends on the root.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
from pathlib import Path
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
DEFAULT_REPO = SCRIPT_DIR.parents[1]
|
||||
|
||||
REPO = DEFAULT_REPO
|
||||
SWEEP = REPO / "results" / "sweep"
|
||||
AN = REPO / "artifacts" / "analysis"
|
||||
OUT = SWEEP / "analysis" / "compare_with_grid.csv"
|
||||
|
||||
|
||||
def configure(repo_root: Path) -> None:
|
||||
"""Rebind the path globals for an explicit repository root."""
|
||||
global REPO, SWEEP, AN, OUT
|
||||
REPO = repo_root.resolve()
|
||||
SWEEP = REPO / "results" / "sweep"
|
||||
AN = REPO / "artifacts" / "analysis"
|
||||
OUT = SWEEP / "analysis" / "compare_with_grid.csv"
|
||||
|
||||
DATASETS = ("xiiotid", "5gnidd")
|
||||
ALPHAS = ("0.25", "0.5", "0.75")
|
||||
|
||||
|
||||
def rows(path: Path) -> list[dict]:
|
||||
with path.open(newline="", encoding="utf-8") as h:
|
||||
return list(csv.DictReader(h))
|
||||
|
||||
|
||||
def f(x: str) -> float:
|
||||
return float(x)
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--repo-root",
|
||||
type=Path,
|
||||
default=DEFAULT_REPO,
|
||||
help="repository root containing results/ and artifacts/ (default: %(default)s)",
|
||||
)
|
||||
args = parser.parse_args(argv)
|
||||
configure(args.repo_root)
|
||||
|
||||
sweep_sel = rows(SWEEP / "analysis" / "selection.csv")
|
||||
master = rows(AN / "final__six_condition_master.csv")
|
||||
out = []
|
||||
for ds in DATASETS:
|
||||
for a in ALPHAS:
|
||||
sw = {f(r["beta"]): f(r["val_rare_f1_per_client_mean"])
|
||||
for r in sweep_sel if r["dataset"] == ds and r["alpha"] == a}
|
||||
path = AN / f"{ds}__alpha{a}__multiseed__validation_per_seed.csv"
|
||||
gd = {f(r["beta"]): f(r["val_rare_macro_f1_per_client_mean"])
|
||||
for r in rows(path) if r["seed"] == "0"}
|
||||
assert set(sw) == set(gd) == {0.0, 0.25, 0.5, 0.75, 1.0}, (ds, a, set(sw), set(gd))
|
||||
pooled = [f(r["selected_beta"]) for r in master
|
||||
if r["dataset"] == ds and f(r["alpha"]) == f(a)]
|
||||
assert len(pooled) == 1, (ds, a, pooled)
|
||||
|
||||
def pick(d):
|
||||
best = max(d.items(), key=lambda kv: (kv[1], -kv[0]))
|
||||
srt = sorted(d.values(), reverse=True)
|
||||
return best[0], srt[0] - srt[1]
|
||||
|
||||
b_sw, m_sw = pick(sw)
|
||||
b_gd, m_gd = pick(gd)
|
||||
rank = 1 + sum(1 for v in gd.values() if v > gd[b_sw])
|
||||
out.append({
|
||||
"dataset": ds, "alpha": a,
|
||||
"beta_sweep_seed0": b_sw, "beta_grid_seed0": b_gd,
|
||||
"beta_grid_pooled": pooled[0],
|
||||
"sweep_equals_grid_s0": int(b_sw == b_gd),
|
||||
"sweep_equals_pooled": int(b_sw == pooled[0]),
|
||||
"grid_s0_equals_pooled": int(b_gd == pooled[0]),
|
||||
"sweep_margin": f"{m_sw:.6f}", "grid_s0_margin": f"{m_gd:.6f}",
|
||||
"max_abs_val_diff_s0": f"{max(abs(sw[b] - gd[b]) for b in sw):.6f}",
|
||||
"sweep_pick_rank_in_grid_s0": rank,
|
||||
})
|
||||
OUT.parent.mkdir(parents=True, exist_ok=True)
|
||||
with OUT.open("w", newline="", encoding="utf-8") as h:
|
||||
w = csv.DictWriter(h, fieldnames=list(out[0]))
|
||||
w.writeheader()
|
||||
w.writerows(out)
|
||||
print(f"written {OUT}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Loaded 100 of 102 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user