MassGAT is a graph-based collective learning framework for untargeted detection and annotation of LC-HRMS data. By modeling LC-MS files as hierarchical graphs where nodes represent ion traces and edges represent chemical relationships (isotopes, adducts, dimers), MassGAT performs simultaneous peak detection and grouping, leveraging analytical redundancy to rescue valid, low-intensity signals.
The pipeline runs in four stages — Trace Segmentation → Graph Construction → Model Inference → Annotation — matching the sections under Usage below.
MassGAT can be run from a local environment or directly inside a container:
- Local: Pixi >= 0.73 and on Windows: Rtools.
- Container: Docker (Windows, Ubuntu) or Apptainer (Ubuntu).
First, clone this repository (e.g. using git):
git clone https://github.com/odisce/MassGAT.git
cd MassGAT| with Pixi | |
|---|---|
| to use cpu | pixi shell -e cpu --locked |
| to use gpu | pixi shell -e gpu --locked |
pixi run install-ionshedData Preparation
A small example is provided in a project called test and can be run directly but if to use other files:
- Replace
testby your project name in all the following commands - First, set up your input directory by creating a folder named
data/test/mzmlin the root of your repository. - Place your LC-MS
.mzMLor.mzXMLfiles (centroid mode) inside.
The structure looks like this:
MassGAT/
└── data/
└── test/
└── mzml/
├── sample_01.mzML
└── sample_02.mzML
Configuration
MassGAT uses two configuration files:
-
config.yaml— Analytical parameters (peak picking, graph construction, correlation thresholds). Changes are automatically detected by the trace segmentation and graph construction scripts, which will reprocess files accordingly. Use the--forceflag to force reprocessing without changing config. -
mass_differences.xlsx— Chemical mass differences (isotopes, adducts, dimers). Entry names should use appropriate prefixes (adduct_,loss_,mod_) to define directionality in annotations. The file contains the following sheets:- isotopes: Isotope mass shifts (mode-independent). Columns:
name,mass_difference,frequency - mods_positive / mods_negative: Adducts/modifications for each ionization mode. Columns:
name,mass_difference,frequency,is_loss(marks entries as losses) - dimers_positive / dimers_negative: Dimer mass shifts for each ionization mode. Columns:
name,mass_difference,frequency - compat_positive / compat_negative: Compatibility for a chain of m/Z differences (e.g., how likely a H2O loss follows Na-H m/Z difference) for synthetic generation of components. Columns:
source_adduct,target_adduct,weight.
When customized, you must regenerate graphs via before training the model (see Training).
- isotopes: Isotope mass shifts (mode-independent). Columns:
-
Trace Segmentation (R): Run the IonShed script to extract peaks and Region of Interest (ROI) signals into
.featherformat.Rscript scripts/ionshed_batch_processing.R data/test/mzml data/test/ionshed_output
-
Graph Construction (Python): Build PyTorch Geometric graphs (
.pt) from the extracted.feathertables.python scripts/build_graphs.py --input_dir data/test/ionshed_output --output_dir data/test/graphs --ionization_mode positive
-
Model Inference (Python): Pass the constructed graphs through the trained MassGAT model. This step evaluates probabilities, groups peaks into chemical components, and optionally annotates them.
python scripts/predict.py --folder data/test/graphs --data_type real --weights weights/model_positive.pth --output_dir data/test/results --min_node_prob 0.5 --with_top_annotations
Key inference arguments:
Argument Description Default --folderPath to the directory containing graph files ( .ptformat)— --weightsPath to trained model weights (e.g., weights/model_positive.pthfor positive-mode,weights/model_negative.pthfor negative-mode)— --output_dirDirectory where results will be saved — --min_node_probProbability threshold above which a peak is kept 0.5--with_top_annotationsAlso output top 5 candidate annotations per component —
Note For interactive visualization: Once the results have been obtained by CLI, you can navigate through the results. To run the
visualization.ipynbnotebook indocs/. Select the (cpu or gpu) python Kernel, if modified, update the project name inos.environ["PROJ_NAME"] = "test"and run the notebook.
- Segmented ionshed features in
.featherformat in subfolderionshed_outputof your project. - Graph representations in
.ptformat in subfoldergraphsof your project. - A final peak list with detection probabilities and, if
--with_top_annotationswas used at Step 3, the top-ranked candidate annotations per component (main ion, isotopes, adducts, losses, dimers).
To retrain MassGAT on custom or synthetic data, first generate synthetic training data, then run the training script.
-
Generate Synthetic Training Data: generate synthetic components for each family type:
python scripts/demo_generate_graphs.py --family <FAMILY_TYPE> --num <NUM_SAMPLES> --out synthetic_dataset/<FAMILY_TYPE> --mode positive --seed 42
--family <FAMILY_TYPE>options:Value Description trueTrue peaks component only falseFalse peaks component only (noise) true_with_noiseTrue peaks component with false peaks included true_singleSingle isolated true peaks false_singleSingle isolated false peaks Example: generate 10,000
true_with_noisesamples:python scripts/demo_generate_graphs.py --family true_with_noise --num 10000 --out synthetic_dataset/true_with_noise --mode positive --seed 42
-
Train MassGAT: Basic training with default hyperparameters:
python scripts/train.py --use_synthetic --synthetic_path synthetic_dataset --num_epochs 15 --batch_size 64 --learning_rate 0.0003 --seed 42
Key training arguments:
Argument Description Default --synthetic_pathPath to synthetic dataset directory — --num_epochsNumber of training epochs 15--batch_sizeBatch size 64--learning_rateLearning rate 0.0003--hidden_dimHidden dimension in the GNN 48--embedding_dimEmbedding dimension 24--encoder_typeSignal encoder: transformerorcnntransformer--block_typeGNN block type: gate,gat, orgcngate--seedRandom seed for reproducibility 42Trained weights are saved to the
weights/directory, named after the ionization--modeused during data generation (e.g.model_positive.pth,model_negative.pth) — matching the files you'd pointpredict.pyat in Step 3 of the Prediction section above.Tracking experiments with MLflow:
mlflow ui --backend-store-uri sqlite:///mlflow.db --port 5001
Then open
http://localhost:5001in your browser to view training metrics and compare runs.
- Inference runs entirely on CPU — no GPU required.
- Typical end-to-end runtime per file (segmentation + graph construction + inference + annotation), on 5 CPU cores:
- ~2.3 minutes for a Time-of-Flight (TOF) file
- ~8.4 minutes for an Orbitrap (QE HF) file
- The model itself is lightweight (~98,000 trainable parameters), so retraining is feasible on CPU-only machines as well.
If you use MassGAT in your research, please cite our preprint:
@article{Pinart2026MassGAT,
author = {Pinart, Paul-Henri and Damont, Annelaure and Dechaumet, Sylvain and Thevenot, Etienne},
title = {MassGAT: a graph-based collective learning approach for untargeted detection and annotation of LC-MS data},
journal = {bioRxiv},
year = {2026},
doi = {10.64898/2026.07.29.741473},
url = {https://doi.org/10.64898/2026.07.29.741473}
}