GlitchGAN
Conditional Dual-discriminator Variational GAN (cDVGAN) for synthesising LIGO gravitational-wave glitch signals. Trained on seven Gravity Spy glitch classes from the O3 observing run.
Overview
GlitchGAN uses a Wasserstein GAN with gradient penalty (WGAN-GP) augmented by a first-derivative discriminator. The derivative discriminator encourages the generator to produce signals with realistic time-domain structure, not just realistic amplitude distributions.
Architecture: Generator + Discriminator + Derivative Discriminator
Classes: Blip, Fast Scattering, Koi Fish, Low Frequency Burst, Scattered Light, Tomte, Whistle
Signal length: 8192 samples @ 4096 Hz (~2 s)
Repository structure
glitchgan/
├── evaluation.ipynb # UMAP + GravitySpy evaluation notebook
├── src/cdvgan/
│ ├── tf/
│ │ ├── model_components.py # Generator / discriminator layers
│ │ ├── gan_models.py # cWGAN, cDVGAN, cDVGAN2, GlitchGAN
│ │ ├── train.py # Training entry point
│ │ └── utils.py # Dataset, callbacks, checkpointing
│ └── utils.py # Signal processing utilities
├── weights/tensorflow/
│ └── generator_210_keras3.keras # Trained generator (epoch 210)
├── models/ # GravitySpy CNN weights (gitignored — see below)
├── data/ # Training data (gitignored — see below)
└── environment.yml
Setup
conda env create -f environment.yml
conda activate cdvgan
The environment installs TensorFlow, Keras 3, GWpy, PyCBC, umap-learn, and GravitySpy.
Note:
environment.ymltargets Apple Silicon (tensorflow-macos / tensorflow-metal). On Linux/HPC replace those withtensorflowand removetensorflow-metal.
Data
The training dataset (DeepExtractor reconstructions of seven LIGO O3 glitch classes — Blip, Fast Scattering, Koi Fish, Low Frequency Burst, Scattered Light, Tomte, Whistle — 35,000 samples) is hosted on HuggingFace: tomdooney/deepextractor-glitch-reconstructions
Download it with the built-in helper:
from glitchgan import download_data
paths = download_data("data/")
Or to also fetch the derivative array needed for cDVGAN training:
paths = download_data("data/", include_derivatives=True)
This places the following files in data/:
data/
├── glitch_GAN_samples_scaled_balanced.npy # (35000, 8192) whitened waveforms
├── glitch_GAN_labels_balanced.npy # (35000, 7) one-hot class labels
├── glitch_GAN_label_order.npy # (7,) class name order
└── glitch_GAN_deriv_samples_balanced.npy # (35000, 8191) derivatives (optional)
Held-out real-data split (second GlitchGAN)
The leak-proof 10% held-out real split and the holdout-trained generator checkpoint used by the experiments below are hosted in the same HuggingFace dataset repo. Download them with:
from glitchgan import download_holdout_data
paths = download_holdout_data()
# paths["holdout_real"] -> data_holdout90/holdout_real.npz
# paths["generator"] -> GAN_outputs_holdout90/cDVGAN/generator_final.keras
Pass include_generator=False to skip the checkpoint and only fetch holdout_real.npz.
GravitySpy model
The GravitySpy O3 CNN (sidd-cqg-paper-O3-model.h5) is not included. It ships with the gravityspy package or can be found in a local GravitySpy clone.
- Install GravitySpy:
pip install gravityspy - Copy the model to
models/sidd-cqg-paper-O3-model.h5 - Set
PATH_TO_REPOinevaluation.ipynbto your GravitySpy clone path
Training
python -m cdvgan.tf.train \
--data-dir data/ \
--variant cDVGAN \
--epochs 500 \
--output-dir GAN_outputs/
See src/cdvgan/tf/train.py for all options.
Evaluation
Open evaluation.ipynb and run all cells. The notebook:
- Loads real glitch data and the trained generator
- Visualises real vs generated waveforms
- Embeds real and generated signals jointly in 3D UMAP space (correlation metric)
- Injects generated signals into whitened H1 background and classifies with GravitySpy
Additional experiments: real-vs-generated discriminability & data augmentation
Peer-review follow-up experiments testing (1) whether GlitchGAN's generated glitches are
statistically distinguishable from real ones, and (2) whether they're useful as training-data
augmentation for a downstream classifier. Both use a leak-proof held-out split of real data and
a second GlitchGAN, trained only on the remaining 90% pool, so the held-out real samples were
never seen during its training — intentionally separate from the main reported model (trained on
100% of the data). All scripts live in scripts/.
1. Leak-proof held-out split + the second, holdout-trained GlitchGAN
The held-out real split and the holdout-trained generator checkpoint are published — see Held-out real-data split above — so most users can skip straight to step 2. To regenerate them from the raw CIT data instead:
python scripts/prepare_holdout_split.py \
--source-npz /path/to/Compleet_set_snr15.npz \
--out-dir data_holdout90/ \
--holdout-out data_holdout90/holdout_real.npz
Splits the raw (pre-oversampling) real dataset 90/10 per class, then rebalances only the 90%
pool, writing it in the same file layout cdvgan.tf.train expects. Train the second GlitchGAN
on that 90% pool:
python -m cdvgan.tf.train \
--data-dir data_holdout90/ \
--variant cDVGAN \
--epochs 500 \
--output-dir GAN_outputs_holdout90/
2. Real-vs-generated discriminability (physical consistency check)
python scripts/classify_real_vs_generated.py \
--holdout-npz data_holdout90/holdout_real.npz \
--generator-checkpoint GAN_outputs_holdout90/cDVGAN/generator_final.keras
python scripts/classify_real_vs_generated_baseline.py \
--holdout-npz data_holdout90/holdout_real.npz \
--generator-checkpoint GAN_outputs_holdout90/cDVGAN/generator_final.keras
Trains a small standalone CNN, and a logistic-regression baseline, to tell held-out real glitches apart from GlitchGAN-generated ones, reporting test accuracy with a 95% Wilson CI. A CI that includes 50% supports "generated samples are statistically indistinguishable from real ones."
The same check under realistic detector noise (bilby aLIGO PSD injection):
python scripts/build_injected_dataset.py \
--holdout-npz data_holdout90/holdout_real.npz \
--generator-checkpoint GAN_outputs_holdout90/cDVGAN/monitor/generator_210.keras \
--out-npz injected_data/injected_real_vs_fake.npz
python scripts/classify_real_vs_generated_noisy.py \
--injected-npz injected_data/injected_real_vs_fake.npz \
--out-dir real_vs_fake_results_noisy
diagnose_real_vs_fake_stats.py, explain_real_vs_fake_ig.py, and explain_real_vs_fake_shap_freq.py
provide diagnostics and interpretability (Integrated Gradients, SHAP) for what the classifier is
actually picking up on.
3. Data augmentation: does synthetic data help a downstream classifier?
python scripts/build_multiclass_dataset.py \
--holdout-npz data_holdout90/holdout_real.npz \
--generator-checkpoint GAN_outputs_holdout90/cDVGAN/monitor/generator_210.keras \
--out-npz multiclass_data/multiclass_datasets_epoch210.npz
python scripts/classify_multiclass.py \
--dataset-npz multiclass_data/multiclass_datasets_epoch210.npz \
--config real_fake_augmented \
--out-dir multiclass_results_epoch210/real_fake_augmented
Builds four training-set variants from the held-out real pool — real (imbalanced), real
(bootstrap-balanced), real+fake (topped up with fresh generated samples to balance), and
fake-only — all evaluated on the same fixed real val/test split so the four configs are directly
comparable. --config accepts real_natural, real_balanced, real_fake_augmented, or fake_only.
To check whether a result (e.g. a few-shot "augmentation rescue" effect) holds across seeds rather than being a lucky draw from a single split:
python scripts/run_multiclass_seed_sweep.py \
--holdout-npz data_holdout90/holdout_real.npz \
--generator-checkpoint GAN_outputs_holdout90/cDVGAN/monitor/generator_210.keras \
--train-samples-per-class 8 \
--val-frac 0.2 \
--target-per-class 5000 \
--seeds 1,2,3,4,5 \
--out-dir multiclass_seed_sweep_fewshot8
python scripts/summarize_all_multiclass_results.py # aggregate across result dirs
python scripts/print_multiclass_results.py # print a results table
Citation
(BibTeX will be added upon publication)
Metadata
Release files for glitchgan 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| glitchgan-1.0.0.tar.gz | 36.6 MB | With provenance | Details for glitchgan-1.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| glitchgan-1.0.0-py3-none-any.whl | Python 3 | none | any | Details for glitchgan-1.0.0-py3-none-any.whl |
Total release size: 36.6 MB
Release files / glitchgan-1.0.0.tar.gz
| Download URL | glitchgan-1.0.0.tar.gz |
|---|---|
| Size | 36.6 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f4bb28d60385ea5433c4dc6ec77072ea162d31e10869b6cfbabd0a1d8162fa89
|
|
BLAKE2b-256 checksum How to use checksums |
13217f82690795025762fdafd08f64ee45b964f695a68bb62b55a7f047d357a1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.
Transparency logRelease files / glitchgan-1.0.0-py3-none-any.whl
| Download URL | glitchgan-1.0.0-py3-none-any.whl |
|---|---|
| Size | 27.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8831c05755bff10a71978bb4c8874692ccbcd4ae55e370f5c84882d29264893d
|
|
BLAKE2b-256 checksum How to use checksums |
cc6b0d43171c410676f152050152b809a06d69a241d487bbd12bd6313809c825
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.
Transparency logSecurity for glitchgan 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for glitchgan-1.0.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.