graphroute 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- graphroute-0.1.0/LICENSE +21 -0
- graphroute-0.1.0/MANIFEST.in +2 -0
- graphroute-0.1.0/PKG-INFO +221 -0
- graphroute-0.1.0/README.md +199 -0
- graphroute-0.1.0/configs/experiment.yaml +33 -0
- graphroute-0.1.0/graphroute/__init__.py +1 -0
- graphroute-0.1.0/graphroute/calibration.py +230 -0
- graphroute-0.1.0/graphroute/cli.py +141 -0
- graphroute-0.1.0/graphroute/config.py +323 -0
- graphroute-0.1.0/graphroute/data.py +65 -0
- graphroute-0.1.0/graphroute/experiment.py +244 -0
- graphroute-0.1.0/graphroute/gnn.py +486 -0
- graphroute-0.1.0/graphroute/graph.py +496 -0
- graphroute-0.1.0/graphroute/losses.py +232 -0
- graphroute-0.1.0/graphroute/models.py +62 -0
- graphroute-0.1.0/graphroute/pool.py +644 -0
- graphroute-0.1.0/graphroute/pool_cache.py +310 -0
- graphroute-0.1.0/graphroute/run.py +474 -0
- graphroute-0.1.0/graphroute/selection.py +138 -0
- graphroute-0.1.0/graphroute/training.py +554 -0
- graphroute-0.1.0/graphroute.egg-info/PKG-INFO +221 -0
- graphroute-0.1.0/graphroute.egg-info/SOURCES.txt +37 -0
- graphroute-0.1.0/graphroute.egg-info/dependency_links.txt +1 -0
- graphroute-0.1.0/graphroute.egg-info/requires.txt +9 -0
- graphroute-0.1.0/graphroute.egg-info/top_level.txt +1 -0
- graphroute-0.1.0/model_registry.py +20 -0
- graphroute-0.1.0/pyproject.toml +30 -0
- graphroute-0.1.0/quickstart.py +100 -0
- graphroute-0.1.0/run_experiments.py +93 -0
- graphroute-0.1.0/setup.cfg +4 -0
- graphroute-0.1.0/tests/test_calibration.py +108 -0
- graphroute-0.1.0/tests/test_config.py +166 -0
- graphroute-0.1.0/tests/test_data.py +75 -0
- graphroute-0.1.0/tests/test_experiment.py +148 -0
- graphroute-0.1.0/tests/test_features.py +173 -0
- graphroute-0.1.0/tests/test_gnn_inductive.py +160 -0
- graphroute-0.1.0/tests/test_oof_stacking.py +105 -0
- graphroute-0.1.0/tests/test_pool_cache.py +408 -0
- graphroute-0.1.0/tests/test_regression.py +100 -0
graphroute-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Brianna Mueller
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: graphroute
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Graph-based dynamic ensembling
|
|
5
|
+
Author: Brianna Mueller
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/briannamueller/GraphRoute
|
|
8
|
+
Project-URL: Issues, https://github.com/briannamueller/GraphRoute/issues
|
|
9
|
+
Requires-Python: <3.13,>=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: torch>=2.0.0
|
|
13
|
+
Requires-Dist: pydantic>=2
|
|
14
|
+
Requires-Dist: torch_geometric>=2.4.0
|
|
15
|
+
Requires-Dist: numpy<2
|
|
16
|
+
Requires-Dist: scikit-learn
|
|
17
|
+
Requires-Dist: scipy
|
|
18
|
+
Requires-Dist: filelock
|
|
19
|
+
Requires-Dist: pyyaml>=6
|
|
20
|
+
Requires-Dist: pytorch-minimize
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# GraphRoute
|
|
24
|
+
|
|
25
|
+
GraphRoute is a graph-based dynamic ensemble selection framework. Given a pool
|
|
26
|
+
of candidate models, a GNN trained over a sample similarity graph learns which
|
|
27
|
+
models to trust for individual cases. Because different models have different
|
|
28
|
+
inductive biases, their reliability varies across the input space. GraphRoute
|
|
29
|
+
learns sample representations where proximity better reflects shared model
|
|
30
|
+
competence. This approach is particularly valuable for problems where models
|
|
31
|
+
optimized for aggregate performance tend to fail on rare edge cases, and where
|
|
32
|
+
failures on such cases are the most consequential.
|
|
33
|
+
|
|
34
|
+
GraphRoute operates in three stages:
|
|
35
|
+
|
|
36
|
+
1. Train a pool of diverse models.
|
|
37
|
+
2. Construct a graph where nodes represent samples and edges encode sample similarity.
|
|
38
|
+
3. Train a GNN to produce per-classifier competence scores.
|
|
39
|
+
|
|
40
|
+
- [Installation](#installation)
|
|
41
|
+
- [Quickstart](#quickstart)
|
|
42
|
+
- [Data and model interface](#data-and-model-interface)
|
|
43
|
+
- [Configure Experiments](#configure-experiments)
|
|
44
|
+
- [Configuration](#configuration)
|
|
45
|
+
- [Reusing a trained pool](#reusing-a-trained-pool)
|
|
46
|
+
- [Development](#development)
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install graphroute
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
GraphRoute requires Python 3.10–3.12, PyTorch 2.0 or newer, and PyTorch
|
|
55
|
+
Geometric 2.4 or newer.
|
|
56
|
+
|
|
57
|
+
The quickstart and experiment runner are repository-level scripts. To use them,
|
|
58
|
+
clone the repository and follow the [development installation](#development-installation).
|
|
59
|
+
|
|
60
|
+
## Quickstart
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
python quickstart.py
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The quickstart trains a pool of four lightweight models on synthetic data, fits
|
|
67
|
+
a graph attention network (GAT), and compares the performance of the resulting
|
|
68
|
+
GNN's dynamic selection with the individual classifiers and fixed ensemble
|
|
69
|
+
baselines.
|
|
70
|
+
|
|
71
|
+
## Data and model interface
|
|
72
|
+
|
|
73
|
+
GraphRoute accepts PyTorch Dataset objects whose samples are (inputs, target) pairs. Datasets with
|
|
74
|
+
custom sample structures can provide a `collate_fn`; see the `fit_graphroute`
|
|
75
|
+
function documentation in
|
|
76
|
+
[`graphroute/run.py`](https://github.com/briannamueller/GraphRoute/blob/main/graphroute/run.py)
|
|
77
|
+
for the required interface. Supply the candidate model instances through the
|
|
78
|
+
ordered `models` list.
|
|
79
|
+
|
|
80
|
+
## Configure Experiments
|
|
81
|
+
|
|
82
|
+
[`run_experiments.py`](https://github.com/briannamueller/GraphRoute/blob/main/run_experiments.py)
|
|
83
|
+
reads the experiment configuration from
|
|
84
|
+
[`configs/experiment.yaml`](https://github.com/briannamueller/GraphRoute/blob/main/configs/experiment.yaml)
|
|
85
|
+
and model factories from
|
|
86
|
+
[`model_registry.py`](https://github.com/briannamueller/GraphRoute/blob/main/model_registry.py).
|
|
87
|
+
Register candidate models in `MODEL_REGISTRY`, specify their names in
|
|
88
|
+
`base.models`, and run:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
python run_experiments.py --config configs/experiment.yaml
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The provided YAML defines one experiment. Uncomment its optional `sweep`
|
|
95
|
+
section to run the Cartesian product of the listed values. Each completed
|
|
96
|
+
configuration and its metrics are saved as a separate JSON file under
|
|
97
|
+
`results/<dataset>/`. Repeating the command skips completed configurations.
|
|
98
|
+
Use `--force` to rerun completed configurations.
|
|
99
|
+
|
|
100
|
+
With the default `data_dir="data"`, GraphRoute reads `train.pt` and `test.pt`
|
|
101
|
+
from `data/<dataset>/`; each file must contain an `(inputs, targets)` tuple saved
|
|
102
|
+
using `torch.save`. `validation.pt` is optional. When it is absent, GraphRoute
|
|
103
|
+
derives validation data from the training set using `val_ratio`.
|
|
104
|
+
|
|
105
|
+
## Configuration
|
|
106
|
+
|
|
107
|
+
Every available setting and its default is defined in
|
|
108
|
+
[`graphroute/config.py`](https://github.com/briannamueller/GraphRoute/blob/main/graphroute/config.py).
|
|
109
|
+
The YAML file uses the same field names. The tables below focus on settings
|
|
110
|
+
whose options require an understanding of GraphRoute itself.
|
|
111
|
+
|
|
112
|
+
### General
|
|
113
|
+
|
|
114
|
+
| Argument | Meaning | Available options |
|
|
115
|
+
| --- | --- | --- |
|
|
116
|
+
| `loss_target` | Sets the GNN training objective. | `"meta_labels"`: minimizes the loss between predicted competence scores and targets that encode each model’s competence.<br>`"ensemble"`: minimizes the loss between the combined prediction and each sample’s ground-truth class label or regression target. |
|
|
117
|
+
|
|
118
|
+
### Model pool training (`base`)
|
|
119
|
+
|
|
120
|
+
| Argument | Meaning | Available options |
|
|
121
|
+
| --- | --- | --- |
|
|
122
|
+
| `base.models` | Names the ordered model pool using entries in the experiment registry. | Nonempty list of registered model names |
|
|
123
|
+
| `base.split_mode` | Chooses how the pool produces out-of-sample predictions for GNN training. | `"oof_stacking"`, `"split_train"` |
|
|
124
|
+
| `base.oof_folds` | Sets the number of folds used for OOF pool training. | Integer of at least `2` |
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
To use all of the training data to train both the base classifiers and the GNN without the optimistic bias caused by evaluating models on their own training samples, base.split_mode=`"oof_stacking"` uses cross-validation to generate out-of-fold predictions for GNN training. The final classifiers used for inference are then trained on the full training set.
|
|
128
|
+
|
|
129
|
+
`split_train` is less computationally expensive because each base classifier is trained only once. It divides the training data into two parts: one is used to train the base classifiers, and the other is used to train the GNN.
|
|
130
|
+
|
|
131
|
+
### Graph construction (`graph`)
|
|
132
|
+
|
|
133
|
+
<table>
|
|
134
|
+
<thead>
|
|
135
|
+
<tr>
|
|
136
|
+
<th>Argument</th>
|
|
137
|
+
<th>Meaning</th>
|
|
138
|
+
<th>Available options</th>
|
|
139
|
+
</tr>
|
|
140
|
+
</thead>
|
|
141
|
+
<tbody>
|
|
142
|
+
<tr>
|
|
143
|
+
<td><code>graph.node_feature_source</code></td>
|
|
144
|
+
<td>Selects the sample representation supplied to the GNN.</td>
|
|
145
|
+
<td rowspan="2">
|
|
146
|
+
<code>"decision_space"</code>: concatenated pool predictions for the sample.<br>
|
|
147
|
+
<code>"feature_space"</code>: original features (flattened if not tabular already).<br>
|
|
148
|
+
<code>"embedding_mean"</code>: averages internal representation each model produces for the sample immediately before its final layer (requires same size embeddings).<br>
|
|
149
|
+
<code>"embedding_concat"</code>: concatenates internal representation each model produces for the sample immediately before its final layer (embedding sizes may differ).<br>
|
|
150
|
+
<code>"hybrid"</code>: decision-space representation and original features concatenated.
|
|
151
|
+
</td>
|
|
152
|
+
</tr>
|
|
153
|
+
<tr>
|
|
154
|
+
<td><code>graph.edge_feature_source</code></td>
|
|
155
|
+
<td>Selects the representation used to measure similarity when constructing graph edges.</td>
|
|
156
|
+
</tr>
|
|
157
|
+
<tr>
|
|
158
|
+
<td><code>graph.k</code></td>
|
|
159
|
+
<td>Sets the number of neighbors per sample.</td>
|
|
160
|
+
<td>Positive integer</td>
|
|
161
|
+
</tr>
|
|
162
|
+
<tr>
|
|
163
|
+
<td><code>graph.neighbor_mode</code></td>
|
|
164
|
+
<td>Selects ordinary nearest neighbors or class-balanced neighbors.</td>
|
|
165
|
+
<td><code>"knn"</code>, <code>"class_balanced"</code></td>
|
|
166
|
+
</tr>
|
|
167
|
+
<tr>
|
|
168
|
+
<td><code>graph.weight_mode</code></td>
|
|
169
|
+
<td>Determines how sample-to-sample edge weights are calculated.</td>
|
|
170
|
+
<td><code>"softmax"</code>, <code>"uniform"</code>, <code>"inverse_distance"</code>, <code>"cmdw"</code></td>
|
|
171
|
+
</tr>
|
|
172
|
+
<tr>
|
|
173
|
+
<td><code>graph.pool_calibrate</code></td>
|
|
174
|
+
<td>Enables or disables classification-pool calibration.</td>
|
|
175
|
+
<td><code>True</code>, <code>False</code></td>
|
|
176
|
+
</tr>
|
|
177
|
+
<tr>
|
|
178
|
+
<td><code>graph.calib_method</code></td>
|
|
179
|
+
<td>Selects the calibration method.</td>
|
|
180
|
+
<td><code>"ts-mix"</code>, <code>"logistic"</code></td>
|
|
181
|
+
</tr>
|
|
182
|
+
</tbody>
|
|
183
|
+
</table>
|
|
184
|
+
|
|
185
|
+
When oof_stacking is combined with embedding-based representations, GraphRoute uses out-of-fold predictions for GNN training, but extracts embeddings from the final base classifiers.
|
|
186
|
+
|
|
187
|
+
### GNN training and dynamic selection (`gnn`)
|
|
188
|
+
|
|
189
|
+
| Argument | Meaning | Available options |
|
|
190
|
+
| --- | --- | --- |
|
|
191
|
+
| `gnn.arch` | Selects the architecture used to learn the dynamic selection rule. | `"gat"`, `"graph_gps"`, `"mlp"` |
|
|
192
|
+
| `gnn.loss` | Selects the GNN training loss. | `"bce"`, `"focal_bce"`, `"soft_bce"`, `"regression"` |
|
|
193
|
+
| `gnn.ens_combination_mode` | Determines how model scores form the final prediction. | `"soft_weighted_voting"`, `"hard_weighted_voting"`, `"soft_voting"`, `"hard_voting"`, `"weighted_mean"` for regression |
|
|
194
|
+
| `gnn.voting_weight_space` | Selects how GNN scores become voting weights; when omitted, GraphRoute chooses based on `loss_target`. | `None`, `"logit"`, `"sig"` |
|
|
195
|
+
| `gnn.fallback` | Selects the fallback rule when no model receives a positive selection weight. | `"uniform"`, `"wacc"`, `"acc"`, `"bacc"` |
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
## Reusing a trained pool
|
|
199
|
+
|
|
200
|
+
GraphRoute automatically caches the results of the computation-heavy base-model training stage under pool_cache/<dataset>/pool_<pool-configuration-hash>/. The cache includes the final trained pool models and the model outputs required to construct the graph and train the GNN. The pool-configuration-hash identifies the specified model architectures and configuration for training base classifiers. Changing only the configuration for graph construction or GNN training leaves the hash unchanged, allowing the trained pool to be reused. Because `dataset` is part of the pool-cache path, use a different dataset name or delete the existing cache when the underlying data or preprocessing changes. Otherwise, GraphRoute may reuse stale models or predictions.
|
|
201
|
+
|
|
202
|
+
## Development
|
|
203
|
+
|
|
204
|
+
### Development installation
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
git clone https://github.com/briannamueller/GraphRoute.git
|
|
208
|
+
cd GraphRoute
|
|
209
|
+
pip install -e .
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
pytest -q
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
The quickstart and test suite run offline on CPU.
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
MIT -- see
|
|
221
|
+
[LICENSE](https://github.com/briannamueller/GraphRoute/blob/main/LICENSE).
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# GraphRoute
|
|
2
|
+
|
|
3
|
+
GraphRoute is a graph-based dynamic ensemble selection framework. Given a pool
|
|
4
|
+
of candidate models, a GNN trained over a sample similarity graph learns which
|
|
5
|
+
models to trust for individual cases. Because different models have different
|
|
6
|
+
inductive biases, their reliability varies across the input space. GraphRoute
|
|
7
|
+
learns sample representations where proximity better reflects shared model
|
|
8
|
+
competence. This approach is particularly valuable for problems where models
|
|
9
|
+
optimized for aggregate performance tend to fail on rare edge cases, and where
|
|
10
|
+
failures on such cases are the most consequential.
|
|
11
|
+
|
|
12
|
+
GraphRoute operates in three stages:
|
|
13
|
+
|
|
14
|
+
1. Train a pool of diverse models.
|
|
15
|
+
2. Construct a graph where nodes represent samples and edges encode sample similarity.
|
|
16
|
+
3. Train a GNN to produce per-classifier competence scores.
|
|
17
|
+
|
|
18
|
+
- [Installation](#installation)
|
|
19
|
+
- [Quickstart](#quickstart)
|
|
20
|
+
- [Data and model interface](#data-and-model-interface)
|
|
21
|
+
- [Configure Experiments](#configure-experiments)
|
|
22
|
+
- [Configuration](#configuration)
|
|
23
|
+
- [Reusing a trained pool](#reusing-a-trained-pool)
|
|
24
|
+
- [Development](#development)
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install graphroute
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
GraphRoute requires Python 3.10–3.12, PyTorch 2.0 or newer, and PyTorch
|
|
33
|
+
Geometric 2.4 or newer.
|
|
34
|
+
|
|
35
|
+
The quickstart and experiment runner are repository-level scripts. To use them,
|
|
36
|
+
clone the repository and follow the [development installation](#development-installation).
|
|
37
|
+
|
|
38
|
+
## Quickstart
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
python quickstart.py
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The quickstart trains a pool of four lightweight models on synthetic data, fits
|
|
45
|
+
a graph attention network (GAT), and compares the performance of the resulting
|
|
46
|
+
GNN's dynamic selection with the individual classifiers and fixed ensemble
|
|
47
|
+
baselines.
|
|
48
|
+
|
|
49
|
+
## Data and model interface
|
|
50
|
+
|
|
51
|
+
GraphRoute accepts PyTorch Dataset objects whose samples are (inputs, target) pairs. Datasets with
|
|
52
|
+
custom sample structures can provide a `collate_fn`; see the `fit_graphroute`
|
|
53
|
+
function documentation in
|
|
54
|
+
[`graphroute/run.py`](https://github.com/briannamueller/GraphRoute/blob/main/graphroute/run.py)
|
|
55
|
+
for the required interface. Supply the candidate model instances through the
|
|
56
|
+
ordered `models` list.
|
|
57
|
+
|
|
58
|
+
## Configure Experiments
|
|
59
|
+
|
|
60
|
+
[`run_experiments.py`](https://github.com/briannamueller/GraphRoute/blob/main/run_experiments.py)
|
|
61
|
+
reads the experiment configuration from
|
|
62
|
+
[`configs/experiment.yaml`](https://github.com/briannamueller/GraphRoute/blob/main/configs/experiment.yaml)
|
|
63
|
+
and model factories from
|
|
64
|
+
[`model_registry.py`](https://github.com/briannamueller/GraphRoute/blob/main/model_registry.py).
|
|
65
|
+
Register candidate models in `MODEL_REGISTRY`, specify their names in
|
|
66
|
+
`base.models`, and run:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
python run_experiments.py --config configs/experiment.yaml
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The provided YAML defines one experiment. Uncomment its optional `sweep`
|
|
73
|
+
section to run the Cartesian product of the listed values. Each completed
|
|
74
|
+
configuration and its metrics are saved as a separate JSON file under
|
|
75
|
+
`results/<dataset>/`. Repeating the command skips completed configurations.
|
|
76
|
+
Use `--force` to rerun completed configurations.
|
|
77
|
+
|
|
78
|
+
With the default `data_dir="data"`, GraphRoute reads `train.pt` and `test.pt`
|
|
79
|
+
from `data/<dataset>/`; each file must contain an `(inputs, targets)` tuple saved
|
|
80
|
+
using `torch.save`. `validation.pt` is optional. When it is absent, GraphRoute
|
|
81
|
+
derives validation data from the training set using `val_ratio`.
|
|
82
|
+
|
|
83
|
+
## Configuration
|
|
84
|
+
|
|
85
|
+
Every available setting and its default is defined in
|
|
86
|
+
[`graphroute/config.py`](https://github.com/briannamueller/GraphRoute/blob/main/graphroute/config.py).
|
|
87
|
+
The YAML file uses the same field names. The tables below focus on settings
|
|
88
|
+
whose options require an understanding of GraphRoute itself.
|
|
89
|
+
|
|
90
|
+
### General
|
|
91
|
+
|
|
92
|
+
| Argument | Meaning | Available options |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| `loss_target` | Sets the GNN training objective. | `"meta_labels"`: minimizes the loss between predicted competence scores and targets that encode each model’s competence.<br>`"ensemble"`: minimizes the loss between the combined prediction and each sample’s ground-truth class label or regression target. |
|
|
95
|
+
|
|
96
|
+
### Model pool training (`base`)
|
|
97
|
+
|
|
98
|
+
| Argument | Meaning | Available options |
|
|
99
|
+
| --- | --- | --- |
|
|
100
|
+
| `base.models` | Names the ordered model pool using entries in the experiment registry. | Nonempty list of registered model names |
|
|
101
|
+
| `base.split_mode` | Chooses how the pool produces out-of-sample predictions for GNN training. | `"oof_stacking"`, `"split_train"` |
|
|
102
|
+
| `base.oof_folds` | Sets the number of folds used for OOF pool training. | Integer of at least `2` |
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
To use all of the training data to train both the base classifiers and the GNN without the optimistic bias caused by evaluating models on their own training samples, base.split_mode=`"oof_stacking"` uses cross-validation to generate out-of-fold predictions for GNN training. The final classifiers used for inference are then trained on the full training set.
|
|
106
|
+
|
|
107
|
+
`split_train` is less computationally expensive because each base classifier is trained only once. It divides the training data into two parts: one is used to train the base classifiers, and the other is used to train the GNN.
|
|
108
|
+
|
|
109
|
+
### Graph construction (`graph`)
|
|
110
|
+
|
|
111
|
+
<table>
|
|
112
|
+
<thead>
|
|
113
|
+
<tr>
|
|
114
|
+
<th>Argument</th>
|
|
115
|
+
<th>Meaning</th>
|
|
116
|
+
<th>Available options</th>
|
|
117
|
+
</tr>
|
|
118
|
+
</thead>
|
|
119
|
+
<tbody>
|
|
120
|
+
<tr>
|
|
121
|
+
<td><code>graph.node_feature_source</code></td>
|
|
122
|
+
<td>Selects the sample representation supplied to the GNN.</td>
|
|
123
|
+
<td rowspan="2">
|
|
124
|
+
<code>"decision_space"</code>: concatenated pool predictions for the sample.<br>
|
|
125
|
+
<code>"feature_space"</code>: original features (flattened if not tabular already).<br>
|
|
126
|
+
<code>"embedding_mean"</code>: averages internal representation each model produces for the sample immediately before its final layer (requires same size embeddings).<br>
|
|
127
|
+
<code>"embedding_concat"</code>: concatenates internal representation each model produces for the sample immediately before its final layer (embedding sizes may differ).<br>
|
|
128
|
+
<code>"hybrid"</code>: decision-space representation and original features concatenated.
|
|
129
|
+
</td>
|
|
130
|
+
</tr>
|
|
131
|
+
<tr>
|
|
132
|
+
<td><code>graph.edge_feature_source</code></td>
|
|
133
|
+
<td>Selects the representation used to measure similarity when constructing graph edges.</td>
|
|
134
|
+
</tr>
|
|
135
|
+
<tr>
|
|
136
|
+
<td><code>graph.k</code></td>
|
|
137
|
+
<td>Sets the number of neighbors per sample.</td>
|
|
138
|
+
<td>Positive integer</td>
|
|
139
|
+
</tr>
|
|
140
|
+
<tr>
|
|
141
|
+
<td><code>graph.neighbor_mode</code></td>
|
|
142
|
+
<td>Selects ordinary nearest neighbors or class-balanced neighbors.</td>
|
|
143
|
+
<td><code>"knn"</code>, <code>"class_balanced"</code></td>
|
|
144
|
+
</tr>
|
|
145
|
+
<tr>
|
|
146
|
+
<td><code>graph.weight_mode</code></td>
|
|
147
|
+
<td>Determines how sample-to-sample edge weights are calculated.</td>
|
|
148
|
+
<td><code>"softmax"</code>, <code>"uniform"</code>, <code>"inverse_distance"</code>, <code>"cmdw"</code></td>
|
|
149
|
+
</tr>
|
|
150
|
+
<tr>
|
|
151
|
+
<td><code>graph.pool_calibrate</code></td>
|
|
152
|
+
<td>Enables or disables classification-pool calibration.</td>
|
|
153
|
+
<td><code>True</code>, <code>False</code></td>
|
|
154
|
+
</tr>
|
|
155
|
+
<tr>
|
|
156
|
+
<td><code>graph.calib_method</code></td>
|
|
157
|
+
<td>Selects the calibration method.</td>
|
|
158
|
+
<td><code>"ts-mix"</code>, <code>"logistic"</code></td>
|
|
159
|
+
</tr>
|
|
160
|
+
</tbody>
|
|
161
|
+
</table>
|
|
162
|
+
|
|
163
|
+
When oof_stacking is combined with embedding-based representations, GraphRoute uses out-of-fold predictions for GNN training, but extracts embeddings from the final base classifiers.
|
|
164
|
+
|
|
165
|
+
### GNN training and dynamic selection (`gnn`)
|
|
166
|
+
|
|
167
|
+
| Argument | Meaning | Available options |
|
|
168
|
+
| --- | --- | --- |
|
|
169
|
+
| `gnn.arch` | Selects the architecture used to learn the dynamic selection rule. | `"gat"`, `"graph_gps"`, `"mlp"` |
|
|
170
|
+
| `gnn.loss` | Selects the GNN training loss. | `"bce"`, `"focal_bce"`, `"soft_bce"`, `"regression"` |
|
|
171
|
+
| `gnn.ens_combination_mode` | Determines how model scores form the final prediction. | `"soft_weighted_voting"`, `"hard_weighted_voting"`, `"soft_voting"`, `"hard_voting"`, `"weighted_mean"` for regression |
|
|
172
|
+
| `gnn.voting_weight_space` | Selects how GNN scores become voting weights; when omitted, GraphRoute chooses based on `loss_target`. | `None`, `"logit"`, `"sig"` |
|
|
173
|
+
| `gnn.fallback` | Selects the fallback rule when no model receives a positive selection weight. | `"uniform"`, `"wacc"`, `"acc"`, `"bacc"` |
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
## Reusing a trained pool
|
|
177
|
+
|
|
178
|
+
GraphRoute automatically caches the results of the computation-heavy base-model training stage under pool_cache/<dataset>/pool_<pool-configuration-hash>/. The cache includes the final trained pool models and the model outputs required to construct the graph and train the GNN. The pool-configuration-hash identifies the specified model architectures and configuration for training base classifiers. Changing only the configuration for graph construction or GNN training leaves the hash unchanged, allowing the trained pool to be reused. Because `dataset` is part of the pool-cache path, use a different dataset name or delete the existing cache when the underlying data or preprocessing changes. Otherwise, GraphRoute may reuse stale models or predictions.
|
|
179
|
+
|
|
180
|
+
## Development
|
|
181
|
+
|
|
182
|
+
### Development installation
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
git clone https://github.com/briannamueller/GraphRoute.git
|
|
186
|
+
cd GraphRoute
|
|
187
|
+
pip install -e .
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
pytest -q
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The quickstart and test suite run offline on CPU.
|
|
195
|
+
|
|
196
|
+
## License
|
|
197
|
+
|
|
198
|
+
MIT -- see
|
|
199
|
+
[LICENSE](https://github.com/briannamueller/GraphRoute/blob/main/LICENSE).
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
dataset: my_dataset
|
|
2
|
+
data_dir: data
|
|
3
|
+
num_classes: 10
|
|
4
|
+
seed: 0
|
|
5
|
+
|
|
6
|
+
base:
|
|
7
|
+
models: [mlp64, mlp128, mlp256]
|
|
8
|
+
split_mode: oof_stacking
|
|
9
|
+
oof_folds: 5
|
|
10
|
+
epochs: 300
|
|
11
|
+
batch_size: 32
|
|
12
|
+
lr: 0.0005
|
|
13
|
+
|
|
14
|
+
graph:
|
|
15
|
+
k: 5
|
|
16
|
+
node_feature_source: decision_space
|
|
17
|
+
edge_feature_source: decision_space
|
|
18
|
+
pool_calibrate: true
|
|
19
|
+
|
|
20
|
+
gnn:
|
|
21
|
+
arch: gat
|
|
22
|
+
hidden_dim: 128
|
|
23
|
+
epochs: 300
|
|
24
|
+
patience: 20
|
|
25
|
+
es_metric: val_acc
|
|
26
|
+
ens_combination_mode: hard_weighted_voting
|
|
27
|
+
voting_weight_space: sig
|
|
28
|
+
|
|
29
|
+
# Uncomment this section to run every combination of the listed values.
|
|
30
|
+
# sweep:
|
|
31
|
+
# seed: [0, 1, 2]
|
|
32
|
+
# graph.k: [3, 5, 10]
|
|
33
|
+
# gnn.arch: [gat, graph_gps]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""GraphRoute: graph-based dynamic ensembling."""
|