Upload README.md with huggingface_hub
Browse files
README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: cc-by-4.0
|
| 3 |
+
library_name: pytorch
|
| 4 |
+
pipeline_tag: feature-extraction
|
| 5 |
+
tags:
|
| 6 |
+
- node2vec
|
| 7 |
+
- graph-embedding
|
| 8 |
+
- metabolomics
|
| 9 |
+
- pytorch-geometric
|
| 10 |
+
- metabolights
|
| 11 |
+
- metabolomics-workbench
|
| 12 |
+
metrics:
|
| 13 |
+
- roc_auc
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
# Node2Vec embeddings for cross-study metabolomics co-response graphs
|
| 17 |
+
|
| 18 |
+
128-dimensional Node2Vec embeddings for two undirected graphs of metabolite co-response
|
| 19 |
+
edges that pass a chi-square validity filter (every expected frequency β₯ 5). Held-out
|
| 20 |
+
link prediction reaches **AUC 0.932** and **0.928**, against degree-only baselines of
|
| 21 |
+
0.826 and 0.888.
|
| 22 |
+
|
| 23 |
+
The graphs, node properties and full pipeline are in the companion dataset repository:
|
| 24 |
+
[kozo2/metabolomics-edges-expected-ge5](https://huggingface.co/datasets/kozo2/metabolomics-edges-expected-ge5).
|
| 25 |
+
|
| 26 |
+
## Files
|
| 27 |
+
|
| 28 |
+
| File | Contents | Size |
|
| 29 |
+
|---|---|---|
|
| 30 |
+
| `edge_ML_filtered_expected_ge5_n2v.pt` | `{embedding: [848, 128] float32, node_id: [848], args: {...}}` | 453 KB |
|
| 31 |
+
| `edge_MLvsMW_filtered_expected_ge5_n2v.pt` | `{embedding: [15758, 128] float32, node_id: [15758], args: {...}}` | 8.6 MB |
|
| 32 |
+
| `node2vec_model.py`, `config.py` | Model definition, training loop, embedding export | β |
|
| 33 |
+
| `heldout_check.py` | The held-out link-prediction evaluation reported below | β |
|
| 34 |
+
|
| 35 |
+
Each file records the exact hyperparameters that produced it under `args`, and
|
| 36 |
+
`node_id[i]` is the original study/assay/feature ID of embedding row `i`.
|
| 37 |
+
|
| 38 |
+
## Using it
|
| 39 |
+
|
| 40 |
+
```python
|
| 41 |
+
import torch
|
| 42 |
+
|
| 43 |
+
ck = torch.load("edge_MLvsMW_filtered_expected_ge5_n2v.pt", weights_only=False)
|
| 44 |
+
z = torch.nn.functional.normalize(ck["embedding"], dim=1) # cosine space
|
| 45 |
+
idx = {node: i for i, node in enumerate(ck["node_id"])}
|
| 46 |
+
|
| 47 |
+
q = z[idx["MTBLS311_0001_00001537"]]
|
| 48 |
+
top = (z @ q).topk(11).indices[1:] # drop self
|
| 49 |
+
print([ck["node_id"][i] for i in top])
|
| 50 |
+
```
|
| 51 |
+
|
| 52 |
+
Scores are cosine similarities β that is the metric the embeddings were trained under
|
| 53 |
+
random walks and evaluated with, so use normalized vectors rather than raw dot products.
|
| 54 |
+
|
| 55 |
+
## Training
|
| 56 |
+
|
| 57 |
+
| | `edge_ML` | `edge_MLvsMW` |
|
| 58 |
+
|---|---|---|
|
| 59 |
+
| graph | 848 nodes, 3,697 edges | 15,758 nodes, 89,277 edges |
|
| 60 |
+
| parameters | 108,544 | 2,017,024 |
|
| 61 |
+
| `embedding_dim` | 128 | 128 |
|
| 62 |
+
| `walk_length` / `context_size` | 20 / 10 | 20 / 10 |
|
| 63 |
+
| `walks_per_node` / negatives | 10 / 1 | 10 / 1 |
|
| 64 |
+
| `p` / `q` | 1.0 / 1.0 (unbiased) | 1.0 / 1.0 (unbiased) |
|
| 65 |
+
| `batch_size` / `lr` / optimizer | 128 / 0.01 / SparseAdam | 128 / 0.01 / SparseAdam |
|
| 66 |
+
| epochs / wall time | 200 / 31 s | 200 / 3 m 05 s |
|
| 67 |
+
| loss, first β last | 9.02 β 0.815 | 6.73 β 0.876 |
|
| 68 |
+
|
| 69 |
+
Trained on one NVIDIA H100 NVL. `sparse=True` makes the embedding table the only
|
| 70 |
+
parameter tensor, which is why the optimizer is `SparseAdam`.
|
| 71 |
+
|
| 72 |
+
## Evaluation
|
| 73 |
+
|
| 74 |
+
`heldout_check.py` deduplicates undirected edges, holds out a random 10%, retrains from
|
| 75 |
+
scratch on the remaining 90%, then scores held-out edges against an equal number of
|
| 76 |
+
sampled non-edges by cosine similarity. The control is the preferential-attachment
|
| 77 |
+
baseline `d_u Β· d_v` on training degrees, which answers whether the embedding learned
|
| 78 |
+
anything beyond "popular nodes connect".
|
| 79 |
+
|
| 80 |
+
| | `edge_ML` | `edge_MLvsMW` |
|
| 81 |
+
|---|---|---|
|
| 82 |
+
| train / held-out edges | 3,328 / 369 | 80,350 / 8,927 |
|
| 83 |
+
| nodes isolated by the split | 42 | 413 |
|
| 84 |
+
| **held-out AUC (never seen)** | **0.932** | **0.928** |
|
| 85 |
+
| train AUC (in-sample) | 0.985 | 0.985 |
|
| 86 |
+
| degree baseline (held-out) | 0.826 | 0.888 |
|
| 87 |
+
| margin over baseline | +0.106 | +0.040 |
|
| 88 |
+
|
| 89 |
+
**Species neighbour purity** β of each node's 10 nearest embeddings by cosine, the
|
| 90 |
+
fraction sharing its species label β is 48.8% overall for `edge_ML` and 59.2% for
|
| 91 |
+
`edge_MLvsMW`, rising to 75β79% for the dominant host species. For the bipartite
|
| 92 |
+
`edge_MLvsMW` graph, the same measure on *source database* gives 67.5% overall (75.4% ST,
|
| 93 |
+
47.7% MTBLS).
|
| 94 |
+
|
| 95 |
+
## Caveats
|
| 96 |
+
|
| 97 |
+
- **Training budget matters more than it looks.** At 20 epochs, `edge_ML` scored a
|
| 98 |
+
held-out AUC of 0.791 β *below* its own 0.826 degree baseline. The embeddings only beat
|
| 99 |
+
preferential attachment once training converges. `--epochs` defaults to 200 for this
|
| 100 |
+
reason; do not shorten it without re-running `heldout_check.py`.
|
| 101 |
+
- On `edge_MLvsMW` the margin over the degree baseline is thin (+0.040). That graph is
|
| 102 |
+
bipartite with a few very high-degree studies, so much of its link structure is
|
| 103 |
+
explained by degree alone.
|
| 104 |
+
- `edge_MLvsMW` loss is flat from about epoch 19, so 200 epochs is more budget than that
|
| 105 |
+
graph needs.
|
| 106 |
+
- Embeddings are transductive: there is no way to embed a node that was not in the
|
| 107 |
+
training graph without retraining.
|