| --- |
| license: cc-by-nc-sa-4.0 |
| library_name: pytorch |
| pipeline_tag: graph-ml |
| tags: |
| - graph-neural-networks |
| - histopathology |
| - self-supervised-learning |
| - pytorch-geometric |
| - graph-representation-learning |
| - edge-features |
| --- |
| |
| # GrapHist++: Edge-Informed Graph Self-Supervised Learning for Histopathology |
|
|
| GrapHist++ encodes a histopathology tile as a **cell graph** (one node per nucleus, edges |
| from a Delaunay triangulation pruned at 100 µm) and embeds it with a self-supervised |
| **ACM-GINEConv** encoder. It extends [GrapHist](https://huggingface.co/ogutsevda/graphist) |
| ([arXiv:2603.00143](https://arxiv.org/abs/2603.00143)) by making the **edges carry |
| information**: each edge holds a 75-dimensional descriptor of the tissue between two cells, |
| and the encoder injects those features into message passing instead of treating edges as mere |
| connectivity. |
|
|
| **Trained on 11,149,499 cell graphs from TCGA-BRCA**, 100 epochs, batch 2048, no labels. The |
| objective is GraphMAE-style masked node-feature reconstruction (mask 50 %, scaled cosine |
| error, α = 3) plus a **VICReg** variance/covariance term on the pooled graph embedding, which |
| keeps all embedding dimensions in use (final `pca_1` 0.17, effective dimension 11.9). |
|
|
| Encoder 7.98 M parameters (9.29 M on the inference path, which also runs the projection; |
| 10.53 M for the full pre-training model), 512-dim embeddings, 0.093 ms/patch at batch 48 on an |
| H200. |
|
|
| ## Results |
|
|
| Slide-level MIL, transfer to unseen cohorts (test macro-F1 %, best of three MIL heads): |
|
|
| | | BRACS | BreakHis | BACH | |
| |---|:--:|:--:|:--:| |
| | GrapHist (v1) | 60.30 | 89.37 | **69.16** | |
| | **GrapHist++** | **69.00** | **95.53** | 68.98 | |
|
|
| Survival on TCGA-BRCA (Cox PH, C-index): **0.793**, vs 0.763 for v1, 0.724 MAE, 0.632 DINOv2. |
| Cell-type identification and patch-level subtyping are in [`DATA.md`](DATA.md), which maps |
| every artifact here to the result it reproduces. |
|
|
| ## What's in this repo |
|
|
| ``` |
| graphist_v2.pt the model. 126,597,010 B, md5 81a2e6b91cefff0bbbc13c6fd318ee78 |
| modeling/ code to load and run it, plus the graph-path helper |
| graphs/ cell graphs: TCGA-BRCA (11.1 M, pre-training), BACH, BRACS, |
| BreakHis, SPIDER-breast |
| embeddings/ embeddings from this model: slide-level (4 cohorts), cell-level (22 sets) |
| baselines/ DINOv2, MAE and GrapHist v1 features for the comparison rows |
| labels/ TCGA-BRCA clinical table and slide labels |
| studies/ data for the side analyses: homophily, AdapterGNN, preprocessing runtime |
| upstream_v1/ mirror of the original GrapHist v1 releases |
| ``` |
|
|
| To run the model on your own graphs you need only `graphist_v2.pt` and `modeling/`. To |
| reproduce a published number you also need that dataset's `normalization.json` from |
| `graphs/<cohort>/`, since the transforms are part of the pipeline. See [`DATA.md`](DATA.md). |
|
|
| Training, evaluation and analysis code lives in |
| [github.com/Ace3Z/GrapHist-V2](https://github.com/Ace3Z/GrapHist-V2). |
|
|
| > ⚠️ **If you use `graphs/`, run `modeling/rebase_graph_paths.py` first.** The label CSVs store |
| > bare filenames and the loader resolves them against the working directory, so without this |
| > step every graph is silently dropped. `DATA.md` has the commands and the expected counts. |
|
|
| ## Usage |
|
|
| ```python |
| from huggingface_hub import snapshot_download |
| path = snapshot_download(repo_id="Ace3Z/graphist-v2") |
| ``` |
|
|
| Three arguments are **load-critical**. `build_model` reads two of them with defaults that do |
| not match this checkpoint, and the third has no default at all: |
|
|
| | Argument | Must be | If wrong | |
| |---|---|---| |
| | `edge_distance_in_proj` | `False` | `edge_input_proj` built as (512, **75**); checkpoint has (512, **74**) | |
| | `encoder_norm` | `"layer"` | `encoder.layer_norms.*` missing from the model | |
| | `concat_hidden` | `True` | `AttributeError` if omitted; (512, 512) instead of (512, **2560**) if `False` | |
|
|
| ```python |
| import sys, torch |
| sys.path.insert(0, f"{path}/modeling") |
| from models import build_model |
| |
| class Args: |
| encoder = decoder = "acm_gineconv" |
| num_features = 96 # per-cell features |
| num_edge_features = 75 # per-edge features (projection sees 74; distance excluded) |
| num_hidden = 512 |
| num_layers = 5 |
| concat_hidden = True # load-critical |
| encoder_norm = "layer" # load-critical |
| edge_distance_in_proj = False # load-critical |
| input_norm = "none" |
| batchnorm = False |
| activation = "prelu" |
| loss_fn = "sce" |
| alpha_l = 3 |
| mask_rate = 0.5 |
| replace_rate = 0.1 |
| drop_edge_rate = 0.0 |
| vicreg_var_weight = 0.05 # training only |
| vicreg_cov_weight = 0.002 |
| vicreg_gamma = 1.0 |
| |
| model = build_model(Args()) |
| ckpt = torch.load(f"{path}/graphist_v2.pt", map_location="cpu", weights_only=False) |
| model.load_state_dict(ckpt["model_state_dict"], strict=True) # note the key name |
| model.eval() |
| |
| # x: [num_nodes, 96] edge_index: [2, num_edges] edge_attr: [num_edges, 75] |
| # batch: [num_nodes] graph assignment (zeros for a single graph) |
| with torch.no_grad(): |
| node_emb = model.embed(x, edge_index, edge_attr, batch) # -> [num_nodes, 512] |
| ``` |
|
|
| Region- and slide-level embeddings are means over node embeddings. To match the published |
| numbers, apply the transforms used at training time: `NormalizeData` with the dataset's |
| `normalization.json`, then `AddVirtualNode`. Both are in `modeling/graphist_utils.py`. |
|
|
| ### Requirements |
|
|
| Inference needs only `torch`, `torch_geometric`, `numpy` and `pandas`. |
|
|
| | | Trained with | Also verified on | |
| |---|---|---| |
| | Python | 3.10 | 3.10 | |
| | torch | 2.2.2 (CUDA 11.8) | 2.10.0 (CUDA 12.8) | |
| | torch_geometric | 2.5.2 | 2.7.0 | |
| | numpy | 1.26.4 | 2.2.6 | |
| | pandas | 2.2.2 | 2.3.3 | |
| |
| Tested at both ends of that range, and on both numpy 1.x and 2.x. Newer versions also work; |
| these are floors, not a supported ceiling. CPU-only inference works. |
| |
| Using the released data needs a little more: `h5py` (the embedding files are HDF5), |
| `scikit-learn` 1.5+ for the cell-level probe, and `lifelines` 0.30 for the survival analysis. |
| |
| > `modeling/models/acm_gin.py` is required even though this model never uses it: |
| > `edcoder.py` imports it at module level. |
|
|
| ## Graph format |
|
|
| | Tensor | Shape | Meaning | |
| |---|---|---| |
| | `x` | `[num_nodes, 96]` | per-cell morphology, texture and colour features | |
| | `edge_index` | `[2, num_edges]` | Delaunay edges, pruned at 100 µm | |
| | `edge_attr` | `[num_edges, 75]` | column 0 = centroid distance (µm); 1–74 describe the inter-cellular region | |
|
|
| The v1 releases use a 1-dimensional `edge_attr` (distance only) and are **not** interchangeable |
| with this model in either direction. |
|
|
| ## Verification |
|
|
| `build_model` + `load_state_dict(strict=True)` returns 0 missing / 0 unexpected keys using only |
| the files shipped here. All 397 BACH slide embeddings regenerate from this checkpoint at |
| minimum cosine similarity **0.9999999997** against the published set. As a control, a |
| different checkpoint scores 0.256 mean cosine on the same comparison, so the test discriminates |
| and these weights are the ones behind the released embeddings. |
|
|
| ## Datasets used |
|
|
| This release is built from seven public cohorts. If you use it, please cite GrapHist **and** |
| the source cohort(s) your work touches. |
|
|
| | Cohort | Used for | Source | |
| |---|---|---| |
| | **TCGA-BRCA** | pre-training (11.1 M graphs), slide-level evaluation, survival | [GDC Data Portal](https://portal.gdc.cancer.gov/) | |
| | **BACH** (ICIAR 2018) | slide-level subtyping, homophily | [Grand Challenge](https://iciar2018-challenge.grand-challenge.org/) | |
| | **BRACS** | slide-level subtyping, homophily | [bracs.icar.cnr.it](https://www.bracs.icar.cnr.it/) | |
| | **BreakHis** | slide-level subtyping, homophily | [P&D Lab, UFPR](https://web.inf.ufpr.br/vri/databases/breast-cancer-histopathological-database-breakhis/) | |
| | **NuCLS** | cell-type identification, homophily | [NuCLS](https://sites.google.com/view/nucls/home) | |
| | **PanNuke** | cell-type identification, homophily | [TIA Centre, Warwick](https://warwick.ac.uk/fac/sci/dcs/research/tia/data/pannuke/) | |
| | **SPIDER-breast** | patch-level subtyping | [histai/SPIDER-breast](https://huggingface.co/datasets/histai/SPIDER-breast) | |
|
|
| <details> |
| <summary>BibTeX for the source cohorts</summary> |
|
|
| ```bibtex |
| @article{weinstein2013cancer, |
| title={The cancer genome atlas pan-cancer analysis project}, |
| author={Weinstein, John N and Collisson, Eric A and Mills, Gordon B and Shaw, Kenna R and |
| Ozenberger, Brad A and Ellrott, Kyle and Shmulevich, Ilya and Sander, Chris and |
| Stuart, Joshua M}, |
| journal={Nature Genetics}, volume={45}, number={10}, pages={1113--1120}, year={2013}, |
| publisher={Nature Publishing Group} |
| } |
| |
| @article{aresta2019bach, |
| title={{BACH}: Grand challenge on breast cancer histology images}, |
| author={Aresta, Guilherme and Ara{\'u}jo, Teresa and Kwok, Scotty and |
| Chennamsetty, Sai Saketh and Safwan, Mohammed and Alex, Varghese and others}, |
| journal={Medical Image Analysis}, volume={56}, pages={122--139}, year={2019}, |
| publisher={Elsevier} |
| } |
| |
| @article{brancati2022bracs, |
| title={{BRACS}: A Dataset for BReAst Carcinoma Subtyping in {H\&E} Histology Images}, |
| author={Brancati, Nadia and Anniciello, Anna Maria and Pati, Pushpak and Riccio, Daniel and |
| Scognamiglio, Giosu{\`e} and Jaume, Guillaume and De Pietro, Giuseppe and |
| Di Bonito, Maurizio and Foncubierta, Antonio and Botti, Gerardo and others}, |
| journal={Database}, volume={2022}, pages={baac093}, year={2022}, |
| publisher={Oxford University Press UK} |
| } |
| |
| @article{spanhol2015dataset, |
| title={A dataset for breast cancer histopathological image classification}, |
| author={Spanhol, Fabio A and Oliveira, Luiz S and Petitjean, Caroline and Heutte, Laurent}, |
| journal={IEEE Transactions on Biomedical Engineering}, volume={63}, number={7}, |
| pages={1455--1462}, year={2015}, publisher={IEEE} |
| } |
| |
| @article{amgad2022nucls, |
| title={{NuCLS}: A scalable crowdsourcing approach and dataset for nucleus classification and |
| segmentation in breast cancer}, |
| author={Amgad, Mohamed and Atteya, Lamees A and Hussein, Hagar and Mohammed, Kareem Hosny and |
| Hafiz, Ehab and Elsebaie, Maha AT and Alhusseiny, Ahmed M and |
| AlMoslemany, Mohamed Atef and Elmatboly, Abdelmagid M and Pappalardo, Philip A and others}, |
| journal={GigaScience}, volume={11}, pages={giac037}, year={2022}, |
| publisher={Oxford University Press} |
| } |
| |
| @article{gamper2020pannuke, |
| title={{PanNuke} dataset extension, insights and baselines}, |
| author={Gamper, Jevgenij and Koohbanani, Navid Alemi and Benes, Ksenija and Graham, Simon and |
| Jahanifar, Mostafa and Khurram, Syed Ali and Azam, Ayesha and Hewitt, Katherine and |
| Rajpoot, Nasir}, |
| journal={arXiv preprint arXiv:2003.10778}, year={2020} |
| } |
| |
| @article{nechaev2025spider, |
| title={{SPIDER}: A Comprehensive Multi-Organ Supervised Pathology Dataset and Baseline Models}, |
| author={Nechaev, Dmitry and Pchelnikov, Alexey and Ivanova, Ekaterina}, |
| year={2025}, eprint={2503.02876}, archivePrefix={arXiv}, primaryClass={cs.CV} |
| } |
| ``` |
| </details> |
|
|
| ## Licence and citation |
|
|
| Released `cc-by-nc-sa-4.0`. Everything here is *derived cell-level features*, not images. |
| SPIDER-breast is `cc-by-nc-4.0`, research use only, and its terms travel with the derived |
| graphs. `labels/tcga_brca_clinical.tsv` is the open-access GDC clinical export, redistributed |
| under TCGA's open-access terms. The source cohorts keep their own licences. |
|
|
| ```bibtex |
| @article{ogut2026graphist, |
| title = {GrapHist: Graph Self-Supervised Learning for Histopathology}, |
| author = {{\"O}{\u{g}}{\"u}t, Sevda and Vincent-Cuaz, C{\'e}dric and |
| Dubljevic, Natalia and Hurtado, Carlos and Subramanian, Vaishnavi and |
| Frossard, Pascal and Thanou, Dorina}, |
| year = {2026}, |
| eprint = {2603.00143}, |
| archivePrefix = {arXiv}, |
| primaryClass = {cs.CV} |
| } |
| ``` |
|
|
| Built on GraphMAE (Hou et al., 2022), ACM (Luan et al., 2022), GINEConv (Hu et al., 2020) and |
| VICReg (Bardes et al., 2022). |
|
|
| This work was done by [**Mahbod Tajdini**](https://mahbodtajdini.com) and [**Tomás Gadea Alcaide**](https://tomasgadea.com/), supervised by members of |
| [LTS4, EPFL](https://www.epfl.ch/labs/lts4/). |
|
|
| Training, evaluation and analysis code: |
| [github.com/Ace3Z/GrapHist-V2](https://github.com/Ace3Z/GrapHist-V2). This repository holds the |
| model, the code needed to load it, and the data. |
|
|