|
| 1 | +# mPCG Wav2Vec |
| 2 | + |
| 3 | +Code for augmentation-supported fine-tuning of a pre-trained Wav2Vec 2.0 encoder for abnormal |
| 4 | +heart-sound classification, with synthetic data generated by denoising-diffusion models |
| 5 | +(WaveGrad and DiffWave). This is the code for: |
| 6 | + |
| 7 | +> M. Marocchi, M. Fynn, K. Mandana, Y. Rong. *Scaling to Multimodal and Multichannel Heart Sound |
| 8 | +> Classification with Synthetic and Augmented Biosignals.* arXiv:2509.11606, 2025. |
| 9 | +> https://arxiv.org/abs/2509.11606 |
| 10 | +
|
| 11 | +The augmentation and generative synthetic-signal approach builds on and is inspired by: |
| 12 | + |
| 13 | +> L. Abbott, M. Marocchi, M. Fynn, Y. Rong, S. Nordholm. *Generative Deep Learning and Signal |
| 14 | +> Processing for Data Augmentation of Cardiac Auscultation Signals: Improving Model Robustness |
| 15 | +> Using Synthetic Audio.* arXiv:2410.10125, 2025. https://arxiv.org/abs/2410.10125 |
| 16 | +
|
| 17 | +## Overview |
| 18 | + |
| 19 | +The pipeline covers three classification settings and one synthetic-generation stage: |
| 20 | + |
| 21 | +| Setting | Data | Model | |
| 22 | +|---|---|---| |
| 23 | +| Single-channel PCG | CinC 2016 (16 kHz) | Wav2Vec 2.0 + MLP head | |
| 24 | +| PCG + ECG | Training-A (4.125 kHz) | two-branch fusion (`big_rnn:2:wav2vec`) | |
| 25 | +| Multichannel PCG | wearable vest (4.125 kHz) | Wav2Vec 2.0 + time-varying sinc beamformer, optional LoRA | |
| 26 | +| Synthetic generation | CinC / vest | DiffWave and WaveGrad (mel- and label-conditioned) | |
| 27 | + |
| 28 | +Signal processing, augmentation and preprocessing are available in both a NumPy form and a |
| 29 | +batched, GPU-capable tensor form (`mpcg_wav2vec.signalproc.torchproc`, |
| 30 | +`mpcg_wav2vec.augment.torchaug`) that operate on whole batches at once. |
| 31 | + |
| 32 | +## Layout |
| 33 | + |
| 34 | +``` |
| 35 | +src/mpcg_wav2vec/ |
| 36 | + signalproc/ filtering, normalisation, Schmidt despiking, resampling, mel-spectrograms, |
| 37 | + segmentation; batched tensor equivalents in torchproc.py |
| 38 | + augment/ HPSS, noise, time/amplitude warp, parametric EQ, baseline wander (+ real-noise |
| 39 | + sources); batched tensor augmentation in torchaug.py |
| 40 | + datasets/ CinC / vest / generative / generated loaders, label vocabularies, schedules |
| 41 | + generative/ DiffWave, WaveGrad, diffusion schedules, samplers, trainer, generation |
| 42 | + classify/ Wav2Vec classifier, two-branch fusion, beamformer, metrics, trainer, evaluation, SVM |
| 43 | + experiments/ runners for the three settings + synthetic-schedule and leave-source-DB-out |
| 44 | + cli.py command-line entry point |
| 45 | +tests/ unit, smoke and numerical-equivalence tests |
| 46 | +docs/ REPRODUCE.md (all experiments/ablations) and DATA.md (data acquisition) |
| 47 | +scripts/ run_generators.sh, run_ablations.sh |
| 48 | +``` |
| 49 | + |
| 50 | +## Install |
| 51 | + |
| 52 | +```bash |
| 53 | +uv venv && uv sync # or: pip install -e . |
| 54 | +``` |
| 55 | + |
| 56 | +The Wav2Vec 2.0 encoder (`facebook/wav2vec2-base-960h`) is downloaded from Hugging Face on first |
| 57 | +use; set `HF_HUB_OFFLINE=1` once it is cached. |
| 58 | + |
| 59 | +## Quick start |
| 60 | + |
| 61 | +```bash |
| 62 | +# Generate a patient-level, label-stratified split CSV from CinC REFERENCE.csv labels |
| 63 | +mpcg-wav2vec make-splits --data-dir <cinc>/training-a --out splits/training-a.csv --folds 5 |
| 64 | + |
| 65 | +# Train a generator, then synthesise an augmentation dataset |
| 66 | +mpcg-wav2vec gen-train --model diffwave --data-dir <cinc> --csv <ref.csv> --output-dir modelout/diffwave |
| 67 | +mpcg-wav2vec gen-sample --model diffwave --weights modelout/diffwave/weights.pt \ |
| 68 | + --data-dir <cinc> --csv <ref.csv> --output-dir generated/diffwave --per-item 3 |
| 69 | + |
| 70 | +# Classification |
| 71 | +mpcg-wav2vec classify-cinc --data-dir <cinc> --csv <ref.csv> --mode pcg --fs 16000 |
| 72 | +mpcg-wav2vec classify-cinc --data-dir <traina> --csv <ref.csv> --mode pcg_ecg --fs 4125 |
| 73 | +mpcg-wav2vec classify-vest --data-dir <vest> --csv <ref.csv> --channels 1,2,3,4,5,6 --lora |
| 74 | +``` |
| 75 | + |
| 76 | +Every command accepts `--max-batches` (classification) / `--max-train-batches` (generation) for |
| 77 | +quick smoke runs. See **[docs/REPRODUCE.md](docs/REPRODUCE.md)** for the full experiment and |
| 78 | +ablation matrix, and **[docs/DATA.md](docs/DATA.md)** for data acquisition and the expected |
| 79 | +on-disk layout. |
| 80 | + |
| 81 | +**Monitoring & options.** Pass `--logdir runs/<name>` to any train/classify command to log |
| 82 | +metrics (and, for generators, periodic generated audio + mel images) to TensorBoard |
| 83 | +(`tensorboard --logdir runs`). Classification uses cross-entropy by default; the vest command |
| 84 | +also accepts `--loss contrastive-focal` (supervised-contrastive + cross-entropy + center loss). |
| 85 | +Generator training rearranges heart cycles by default when `--segment-dir` is given |
| 86 | +(`--no-rearrange` to disable); generation never rearranges. |
| 87 | + |
| 88 | +## Data layout |
| 89 | + |
| 90 | +* Records readable by `wfdb` at `<data-dir>/<patient>` (CinC/Training-A: channel 0 = PCG, |
| 91 | + channel 1 = ECG; vest: one channel per microphone). |
| 92 | +* A reference CSV with a `patient` column, a binary label column (`abnormality`/`label`), and |
| 93 | + per-fold split columns (`split`, `split2`, …) valued `train`/`valid`/`test`. |
| 94 | + |
| 95 | +## Preprocessing |
| 96 | + |
| 97 | +Following the paper, PCG is resampled, Schmidt spike-removed, band-limited (25–450 Hz) and |
| 98 | +abs-max normalised; ECG is resampled, band-limited (2–40 Hz) and abs-max normalised. Recordings |
| 99 | +are segmented into overlapping windows (4 s for CinC/Training-A, 2 s for vest; 0.25 s overlap; |
| 100 | +first 0.3 s discarded). Classification runs at 16 kHz for CinC and 4.125 kHz for Training-A and |
| 101 | +the vest data. |
| 102 | + |
| 103 | +## Tests |
| 104 | + |
| 105 | +```bash |
| 106 | +uv run --with pytest pytest |
| 107 | +``` |
| 108 | + |
| 109 | +The suite covers the signal processing, augmentation, generators, datasets/schedules and |
| 110 | +classifier, and checks that the NumPy and batched tensor preprocessing paths agree. |
| 111 | + |
| 112 | +## Citation |
| 113 | + |
| 114 | +If you use this code, please cite the Marocchi et al. 2025 paper (this work), and the |
| 115 | +Abbott et al. 2025 paper for the augmentation and synthetic-signal methods it builds on. See |
| 116 | +[CITATION.cff](CITATION.cff) for both entries. |
0 commit comments