GrapHist++: Edge-Informed Graph Self-Supervised Learning for Histopathology
Pre-trained weights, cell graphs and embeddings for the edge-informed extension of
GrapHist. GrapHist encodes a slide as a sparse graph
of cells and pre-trains an ACM-GIN encoder with masked feature reconstruction. GrapHist++ keeps
that recipe and changes two things: each edge carries a 75-dimensional descriptor of the tissue
between the two cells, and a VICReg variance/covariance term is added to the objective to stop
the representation collapsing.
Data manual:DATA.md, mapping every artifact here to the result it reproduces
Results
Slide-level MIL, transfer to unseen cohorts (test macro-F1 %, best of three MIL heads):
BRACS
BreakHis
BACH
GrapHist
60.30
89.37
69.16
GrapHist++
69.00
95.53
68.98
Survival on TCGA-BRCA (Cox PH, C-index): 0.793, against 0.763 for GrapHist, 0.724 MAE,
0.632 DINOv2. Cell-type identification (macro-F1 %): PanNuke 20× breast 58.57, 40× breast
58.38, NuCLS 7-class 27.09. The encoder is 7.98 M parameters, 9.29 M with the projection embed() runs through, inside a
10.53 M pre-training checkpoint; it embeds a patch in 0.093 ms at 0.327 GB peak memory (BACH,
batch size 48, H200).
Without VICReg the encoder collapses (pca_1 ≈ 0.5, effective dimension ≈ 2 of 512); with it
the same 100-epoch run finishes at 0.17 and 11.9. The term is training-only.
What's here
graphist_v2.pt the released encoder (127 MB, md5 81a2e6b91cefff0bbbc13c6fd318ee78)
modeling/ build_model factory and the ACM-GINEConv backbone
graphs/ cell graphs: TCGA-BRCA, BACH, BRACS, BreakHis, SPIDER-breast
embeddings/ precomputed slide- and cell-level embeddings
baselines/ DINOv2, MAE and GrapHist v1 embeddings for comparison
labels/ slide labels and the TCGA-BRCA clinical export
studies/ homophily, AdapterGNN and preprocessing-runtime artifacts
upstream_v1/ the original GrapHist graphs, unchanged
The repository is ~1.05 TB, so fetch file by file rather than cloning it. DATA.md gives the
per-cohort commands; the model alone is the six files in the snippet below.
pandas and numpy are needed only by modeling/graphist_utils.py, which holds the input
transforms.
Graphs are PyTorch Geometric objects with x(n, 96), edge_index(2, e), edge_attr(e, 75) and batch. Column 0 of edge_attr is the centroid distance in µm and is used as the
message weight, not as a feature.
Usage
python
1import os, sys, torch
2from huggingface_hub import hf_hub_download
34# Fetch file by file. snapshot_download(allow_patterns=...) is equivalent on5# huggingface-hub >= 1.27, but silently skips LFS files on 1.7.1, which is the6# version the code repository pins, so it would return no checkpoint there.7for f in["graphist_v2.pt","modeling/graphist_utils.py",8"modeling/models/__init__.py","modeling/models/acm_gin.py",9"modeling/models/acm_gineconv.py","modeling/models/edcoder.py",10"modeling/models/utils.py"]:11 hf_hub_download(repo_id="Ace3Z/graphist-v2", filename=f)1213path = os.path.dirname(hf_hub_download(repo_id="Ace3Z/graphist-v2",14 filename="graphist_v2.pt"))15sys.path.insert(0,f"{path}/modeling")16from models import build_model
1718classArgs:19 encoder = decoder ="acm_gineconv"20 num_features =96# per-cell features21 num_edge_features =75# projection sees 74; distance excluded22 num_hidden =51223 num_layers =524 concat_hidden =True# load-critical25 encoder_norm ="layer"# load-critical26 edge_distance_in_proj =False# load-critical27 input_norm ="none"28 batchnorm =False29 activation ="prelu"30 loss_fn ="sce"31 alpha_l =332 mask_rate =0.533 replace_rate =0.134 drop_edge_rate =0.035 vicreg_var_weight =0.05# training only36 vicreg_cov_weight =0.00237 vicreg_gamma =1.03839model = build_model(Args())40ckpt = torch.load(f"{path}/graphist_v2.pt", map_location="cpu", weights_only=False)41model.load_state_dict(ckpt["model_state_dict"], strict=True)42model.eval()43
A graph has to go through the same three transforms the release was trained and evaluated with,
or the embeddings will not match. They ship here, in modeling/graphist_utils.py:
Skipping the transforms raises no error; it just yields different numbers. embed() returns one
row per node including the synthetic virtual node, so a 16-cell graph gives (17, 512); drop
the last row before pooling to a patch vector.
Three arguments decide whether the weights load at all. encoder_norm must be "layer" and
edge_distance_in_proj must be False (both defaults are wrong for this checkpoint), and
concat_hidden must be True, which has no default. Anything else raises a shape or key error.
Licence and citation
Released under the MIT licence, matching the code repository.
That covers what this repository adds. It cannot relicense the source data, and three upstream
terms travel with the derivatives:
What
Upstream terms
upstream_v1/, studies/adaptergnn/graphs_v1/
cc-by-nc-sa-4.0 from the GrapHist v1 datasets: non-commercial and share-alike
graphs/spider_breast/
cc-by-nc-4.0, research use only
baselines/graphist_v1/graphist_v1.pt
apache-2.0, byte-identical to the released GrapHist v1 checkpoint
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, so cite their papers
alongside GrapHist.
1@misc{ogut2026graphist,
2 title = {GrapHist: Graph Self-Supervised Learning for Histopathology},
3 author = {Sevda {\"O}{\u{g}}{\"u}t and C{\'e}dric Vincent-Cuaz and Natalia Dubljevic and
4 Carlos Hurtado and Vaishnavi Subramanian and Pascal Frossard and Dorina Thanou},
5 year = {2026},
6 eprint = {2603.00143},
7 url = {https://arxiv.org/abs/2603.00143},
8}