Documentation generated by AI (Opus 3)
Optimal Experimental Design by Artificial Intelligence — Application to oceanographic observation networks.
- Project Structure
- Dependencies
- Quick Start
- Orchestrator — run_demo.py
- Module 1 — Autoencoder
- Module 2 — GNN
- Module 3 — RL
- Synthetic Data
- Reproducibility
- Output Files
config.py Shared configuration (domain, physics, seeds)
dataset.py Synthetic ocean generator + PyTorch Dataset
01_autoencoder.py Module 1 — AE-UNet MC-Dropout (reconstruction + uncertainty)
02_gnn.py Module 2 — GAT + GraphSAGE (network structure + inductive)
03_rl.py Module 3 — PPO (sensor placement optimization)
run_demo.py Orchestrator (individual | pipeline)
outputs/ Output directory (created automatically)
Outputs are archived in timestamped subfolders, for example outputs/pipeline_20260319_143022_so42_sb7/.
pip install torch numpy scipy matplotlibOptional (for native GATConv/SAGEConv, otherwise manual fallback):
pip install torch-geometric# Complete pipeline (RL → GNN → AE) with demo parameters
python run_demo.py --mode pipeline
# Pipeline + lightweight config evaluation (N★/2) by GNN + AE
python run_demo.py --mode pipeline --eval_light
# Independent modules
python run_demo.py --mode individualReal run (individual, approximately 30-60 min depending on GPU):
python run_demo.py --mode individual \
--seed_ocean 42 --seed_buoys 7 \
--nt 800 --n_buoys 30 \
--ae_epochs 80 --ae_base_ch 32 \
--gnn_epochs 200 \
--rl_steps 50000 --rl_grid_x 16 --rl_grid_y 24 \
--rl_n_min 10 --rl_n_max 40Real run (pipeline with dense/light comparison, approximately 25-50 min depending on GPU):
python run_demo.py --mode pipeline --eval_light \
--seed_ocean 42 --seed_buoys 7 \
--nt 800 --n_buoys 30 \
--ae_epochs 60 --ae_base_ch 32 \
--gnn_epochs 200 \
--rl_steps 50000 --rl_grid_x 16 --rl_grid_y 24 \
--rl_n_min 10 --rl_n_max 40Standalone modules (full training):
python 01_autoencoder.py --train --figures
python 02_gnn.py --train --analyze --inductive
python 03_rl.py --train --evaluate --rl_method pareto
python 03_rl.py --train --evaluate --rl_method efficiency
python 03_rl.py --train --evaluate --rl_method scalarizedGenerate only the nature run figure:
python dataset.py --nt 500 --seed 42run_demo.py
Two execution modes. All three modules share the same nature run and the same initial buoy network (reproducibility via seeds).
individual: AE, GNN and RL each run independently on the initial network.pipeline: RL optimizes the network, then GNN analyzes it, then AE evaluates it.
python run_demo.py --mode pipeline --seed_ocean 42 --seed_buoys 7
python run_demo.py --mode individual --nt 300 --ae_epochs 10| Argument | Description | Default |
|---|---|---|
--mode |
individual or pipeline |
individual |
--seed_ocean |
Nature run seed (SST/SSS fields) | 42 |
--seed_buoys |
Initial buoy network seed | 7 |
--nt |
Number of timesteps in nature run | 200 |
--n_buoys |
Number of buoys in initial network | 30 |
--eval_light |
Enable lightweight config evaluation (N★/2), pipeline mode only | disabled |
--ae_epochs |
AE training epochs | 5 |
--ae_base_ch |
AE base channels (16 = demo, 32 = full) | 16 |
--gnn_epochs |
GAT and GraphSAGE training epochs | 30 |
--rl_steps |
PPO steps (2000 = demo, 50000+ = convergence) | 2000 |
--rl_grid_x |
X resolution of RL candidate grid | 8 |
--rl_grid_y |
Y resolution of RL candidate grid | 12 |
--rl_n_min |
Minimum number of active buoys | 5 |
--rl_n_max |
Maximum number of active buoys | 20 |
--rl_episode_len |
Actions per RL episode | 20 |
--rl_method |
N★ selection method: pareto, efficiency or scalarized |
pareto |
--gif_frames |
Number of frames in RL progression GIF | 40 |
--output_dir |
Output directory | outputs |
01_autoencoder.py
Deterministic AE-UNet with uncertainty via MC-Dropout. Reconstructs SST/SSS fields from partial observations. Produces uncertainty maps, LOO scores and buoy proposals.
# Full training
python 01_autoencoder.py --train --epochs 100
# Training + diagnostic figures
python 01_autoencoder.py --train --figures
# Figures only from checkpoint
python 01_autoencoder.py --figures --checkpoint outputs/ae_best.pt
# Leave-One-Out scoring
python 01_autoencoder.py --score --checkpoint outputs/ae_best.pt
# All at once
python 01_autoencoder.py --train --figures --score| Argument | Description | Default |
|---|---|---|
--train |
Launch training | — |
--score |
Compute LOO scores per sensor | — |
--figures |
Generate diagnostic figures | — |
--seed_ocean |
Nature run seed | 42 |
--seed_buoys |
Buoy position seed | 7 |
--checkpoint |
Checkpoint path to load | outputs/ae_best.pt |
--output_dir |
Output directory | outputs |
--epochs |
Number of epochs | 100 |
--batch_size |
Batch size | 16 |
--lr |
Learning rate (AdamW) | 3e-4 |
--base_ch |
UNet base channels (levels: 2x, 4x, 8x, 16x) | 32 |
--latent_ch |
Latent bottleneck dimension | 64 |
--cond_dim |
FiLM embedding dimension | 32 |
--dropout_p |
MC-Dropout probability | 0.1 |
--w_unobs |
Loss weight on unobserved pixels | 4.0 |
--lambda_grad |
Spatial gradient loss weight | 0.5 |
--huber_delta |
Huber loss threshold | 0.5 |
--n_obs_min |
Minimum observations per sample | 10 |
--n_obs_max |
Maximum observations per sample | 80 |
--n_mc_val |
MC-Dropout passes for validation | 15 |
--n_mc |
MC-Dropout passes for figures | 60 |
02_gnn.py
Graph Attention Network to analyze sensor network structure. Detects redundancies, identifies gaps, evaluates new sensors inductively via GraphSAGE.
# GAT + GraphSAGE training + full analysis
python 02_gnn.py --train --analyze
# With inductive evaluation of hypothetical sensors
python 02_gnn.py --train --analyze --inductive
# Custom positions for inductive evaluation
python 02_gnn.py --train --inductive --new_positions "[(50,100),(120,200)]"
# Analysis only from existing checkpoints
python 02_gnn.py --analyze
# Inductive evaluation only
python 02_gnn.py --inductive --new_positions "[(30,60),(90,180),(140,50)]"| Argument | Description | Default |
|---|---|---|
--train |
Train GAT and GraphSAGE | — |
--analyze |
Full network analysis (contribution, redundancy, coverage) | — |
--inductive |
Evaluate hypothetical sensors via GraphSAGE | — |
--seed_ocean |
Nature run seed | 42 |
--seed_buoys |
Buoy position seed | 7 |
--new_positions |
Hypothetical sensor (x,y) positions | "[(10,20),(80,150),(130,40)]" |
--corr_threshold |
Correlation threshold to create an edge | 0.5 |
--k_nearest |
Number of geographic nearest neighbors | 4 |
--gnn_epochs |
Training epochs | 200 |
--output_dir |
Output directory | outputs |
--n_buoys |
Number of buoys in network | 30 |
03_rl.py
Reinforcement Learning (PPO) to optimize sensor placement on a candidate grid. Produces a Pareto front of information vs number of sensors and compares dense vs light configs.
# PPO training + Pareto evaluation
python 03_rl.py --train --evaluate
# Efficiency method
python 03_rl.py --train --evaluate --rl_method efficiency
# Scalarized method (lambda sweep)
python 03_rl.py --train --evaluate --rl_method scalarized
# Evaluation only from checkpoint
python 03_rl.py --evaluate --rl_method efficiency
# Progression GIF only
python 03_rl.py --gif
# Everything
python 03_rl.py --train --evaluate --gif --rl_method paretopareto(default): info vs N sweep with policy + random, Kneedle elbow, Pareto front.efficiency: eta(N) = info(N) / (1 + log(N)), N★ = argmax(eta). The log(N) softly penalizes large networks.scalarized: trains 4 PPO with increasing lambda as marginal cost per sensor, the best is chosen by eta.
| Argument | Description | Default |
|---|---|---|
--train |
Launch PPO training | — |
--evaluate |
Evaluate network with chosen method | — |
--gif |
Generate animated progression GIF | — |
--rl_method |
pareto, efficiency or scalarized |
pareto |
--seed_ocean |
Nature run seed | 42 |
--seed_buoys |
Seed (reserved for future use) | 7 |
--checkpoint |
RL checkpoint path | outputs/rl_best.pt |
--output_dir |
Output directory | outputs |
--rl_steps |
Total PPO steps (2000 = test, 50000+ = convergence) | 50000 |
--buffer_size |
PPO rollout buffer size | 512 |
--lr |
Learning rate (Adam) | 3e-4 |
--grid_x |
X resolution of candidate grid | 16 |
--grid_y |
Y resolution of candidate grid | 24 |
--n_min |
Minimum number of active buoys | 10 |
--n_max |
Maximum number of active buoys | 40 |
--episode_len |
Actions per episode | 20 |
--w_info |
Information reward weight | 1.0 |
--w_budget |
Budget penalty weight | 0.5 |
--gif_frames |
Number of GIF frames | 80 |
dataset.py
2D+T nature run generator with realistic physical structures: double gyre, meandering zonal front, mesoscale eddies, seasonal cycle, k⁻³ spectral turbulence, SSS coupled to SST.
python dataset.py --nt 500 --seed 42| Argument | Description | Default |
|---|---|---|
--nt |
Number of timesteps | 1000 |
--seed |
Numpy seed | 42 |
--out |
Output figure path | outputs/ocean_nature_run.png |
The set_global_seed(seed) function in config.py fixes numpy, PyTorch CPU, PyTorch GPU and enables deterministic cuDNN mode.
Two seeds control the entire pipeline:
seed_ocean: controls the nature run (SST/SSS fields). Same seed = same ocean data.seed_buoys: controls initial buoy positions. Same seed = same starting network.
To exactly reproduce a run:
python run_demo.py --mode pipeline --seed_ocean 42 --seed_buoys 7The global seed is fixed at the start of each module. All random draws (network initializations, DataLoader, masks, train/test splits, RL resets) are reproducible.
Outputs are archived in timestamped subfolders, identifiable by mode, date and seeds:
outputs/pipeline_20260319_143022_so42_sb7/
outputs/individual_20260319_150100_so42_sb7/
| File | Description |
|---|---|
ae_best.pt |
Best AE model (minimal val RMSE) |
gnn_best.pt |
Best GAT model |
sage_best.pt |
Best GraphSAGE model |
rl_best.pt |
Best PPO policy + active_mask |
| File | Description |
|---|---|
ae_training_curves.png |
Loss / RMSE / deep supervision curves |
ae_network_evaluation.png |
Reconstruction, MC sigma, LOO, gap zones, D-optimal buoys |
ae_uncertainty_density.png |
Uncertainty compared Dense/Medium/Sparse |
| File | Description |
|---|---|
gnn_network_analysis.png |
Contribution, uniqueness, correlation, graph, coverage, barplot |
gnn_network_analysis_rl_optimal.png |
Same on RL network (pipeline mode) |
gnn_network_analysis_rl_light.png |
Same on light config (if --eval_light) |
gnn_inductive_eval.png |
Hypothetical sensor scores (if --inductive) |
| File | Description |
|---|---|
rl_training_curves.png |
Reward, N active, info, cumulative reward |
rl_final_config.png |
Optimal configuration found |
rl_two_configs.png |
Dense (N★) vs light (N★/2) comparison |
rl_progression.gif |
RL learning progression animation |
rl_pareto_front.png |
Info vs N front + marginal gain (pareto method) |
rl_efficiency.png |
Info, eta(N), info vs log cost (efficiency method) |
rl_scalarized.png |
N per lambda, info vs N, eta per lambda (scalarized method) |
| File | Description |
|---|---|
rapport_pipeline_YYYYMMDD.txt |
Full report (pipeline mode) |
rapport_individual_YYYYMMDD.txt |
Full report (individual mode) |
ae_loo_scores.json |
LOO scores per sensor |