- Python 100%
| Fichier | Dernier message de commit | Date du dernier commit |
|---|---|---|
| model | ||
| src/calypso_bvp_denoising | ||
| tests | ||
| train | ||
| use | ||
| .gitignore | ||
| pyproject.toml | ||
| README.md | ||
| requirements.txt | ||
calypso-bvp-denoising
Débruitage appris du signal BVP au poignet, développé pour le projet CALYPSO.
Le système répare les portions d'un signal BVP corrompues par le mouvement, en préservant telles quelles les portions propres. Il combine deux réseaux : Segade, qui détecte les zones d'artefact point par point, et SPEAR, un auto-encodeur convolutif qui reconstruit le signal dans ces zones. La finalité est de rendre exploitables les marqueurs cardiaques (fréquence cardiaque, variabilité) extraits du signal réparé.
Ce dépôt contient le modèle entraîné, prêt à l'emploi, et tout ce qu'il faut pour le reproduire, le ré-entraîner ou l'améliorer.
calypso-denoising/
├── model/
│ ├── spear_best.pt poids du débruiteur livré (36 Mo)
│ ├── segade_fold0_best.pt poids du détecteur d'artefacts (9 Mo)
│ └── config.yaml protocole du modèle livré
├── use/
│ ├── denoise.py débruiter un signal : un .npy entre, un .npy sort
│ └── example/demo.py démonstration avant/après sur signal synthétique
├── train/
│ ├── build_pool.py construire le jeu d'entraînement (DeepBeat + Segade)
│ ├── pool_full_v3_index.npz index exact du jeu du modèle livré
│ └── train.py entraîner SPEAR : graine fixée, garde-fous, convergence
├── tests/run_checks.py vérifications de base
└── src/calypso_bvp_denoising/ le package : modèles, corruptions, pertes, inférence
Installation
Python 3.12 minimum (exigé par les versions figées de NumPy et SciPy).
git clone https://git.interactions-team.fr/aya.bayna/arche-denoising.git && cd arche-denoising
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
pip install -e .
requirements.txt fige les versions avec lesquelles le modèle livré a été construit et
vérifié. Le GPU est optionnel : l'inférence tourne très bien sur CPU ; l'entraînement
utilise automatiquement CUDA ou Apple MPS quand ils sont disponibles.
Pour vérifier que tout est en place :
python tests/run_checks.py
python use/example/demo.py
La démo simule deux minutes de PPG, en corrompt douze secondes, débruite, et écrit
use/example/demo_avant_apres.png avec les trois signaux tracés l'un sous l'autre.
Utiliser le modèle
Entrée attendue : un signal BVP 1D à 64 Hz, dans ses unités d'origine, d'au moins
30 secondes. 64 Hz est la seule fréquence prise en charge ; rééchantillonnez d'abord tout
autre signal (par exemple scipy.signal.resample_poly).
python use/denoise.py mon_signal.npy # écrit mon_signal_denoised.npy (+ mask, + rejected)
Ou depuis Python :
from use.denoise import load_models, denoise_raw
spear, segade = load_models("model/spear_best.pt", "model/segade_fold0_best.pt", "cpu")
denoised, mask, rejected = denoise_raw(x, spear, segade)
Ce qui se passe en interne, fenêtre de 30 s par fenêtre de 30 s, dans l'ordre exact du protocole de validation du modèle :
- recette Guo : passe-bande Butterworth 0,9-5 Hz causal, puis min-max [0,1] ;
- si les battements de la fenêtre filtrée sont déjà réguliers, elle est laissée telle quelle (auto-conditionnement : on ne répare pas ce qui fonctionne) ;
- Segade produit un masque binaire d'artefact (seuil 0,5) ; une fenêtre corrompue à plus
de 75 % est jugée irrécupérable, laissée telle quelle et signalée dans
rejected, à exclure des analyses en aval ; - sinon, les zones marquées sont effacées, reconstruites par SPEAR, et recollées ; hors zones d'artefact, la fenêtre filtrée est conservée telle quelle.
La sortie est donc dans l'espace du filtre ([0,1] par fenêtre), et l'amplitude d'origine est volontairement abandonnée : c'est sur ce signal que s'extraient les marqueurs cardiaques (pics, intervalles battement à battement), qui ne dépendent pas de l'échelle d'amplitude.
Reproduire ou ré-entraîner le modèle
1. Récupérer les données
Le jeu d'entraînement vient de DeepBeat (Stanford), distribué sur Synapse.
Créez un compte sur synapse.org, installez synapseclient,
authentifiez-vous (synapse login), puis :
mkdir -p data/raw/deepbeat && cd data/raw/deepbeat
synapse get syn22006404 --downloadLocation . # train.npz (18,1 Go)
synapse get syn22006006 --downloadLocation . # validate.npz (3,3 Go)
synapse get syn22006407 --downloadLocation . # test.npz (114 Mo)
Prévoir 22 Go de disque pour les fichiers bruts. Ils ne servent qu'à construire le jeu ;
une fois pool_full_v3.npy produit (1,5 Go), ils peuvent être supprimés.
2. Construire le jeu d'entraînement
Le jeu exact du modèle livré se reconstruit depuis son index, fourni dans le dépôt :
python train/build_pool.py --from-index train/pool_full_v3_index.npz
L'index contient les indices précis des 234 999 fenêtres uniques retenues, issues de 109 participants (le critère « zéro artefact selon Segade » est strict : sur les 167 participants de la base, 109 ont au moins une fenêtre entièrement propre). Le jeu est stratifié par participant, avec un plafond commun de fenêtres par personne et une déduplication globale. Le script vérifie l'index (clés, permutation complète, indices uniques et dans les bornes), refuse d'écrire un jeu contenant un doublon, et affiche la composition et l'équilibre pour contrôle.
Pour refaire le protocole de zéro (inventaire complet des trois réservoirs, environ
deux heures de parcours), lancer sans --from-index.
3. Entraîner
python train/train.py --pool data/pool_full_v3.npy --ckpt-dir checkpoints/mon_run
C'est le protocole du modèle livré : graine 20260805 partout (réseau, ordre des lots, corruptions), corruption combinée (bruit plausible, modèle repris de la boîte à outils RRest, plus masquage aléatoire), perte RMSE plus un terme spectral de bande cardiaque 0,9-3 Hz pondéré par λ = 0,7, batch 128, et arrêt par convergence : l'entraînement continue tant que le score de surveillance progresse d'au moins 0,0002, et s'arrête après 5 cycles consécutifs sans progrès. Le modèle livré s'est arrêté au cycle 54 ; son meilleur cycle, le 52, est celui du checkpoint.
Le script embarque quatre garde-fous : il refuse de démarrer si la bande de la perte
diffère de celle déclarée, si le jeu contient un doublon, ou si les fenêtres n'ont pas la
bonne longueur, et il journalise tout dans un fichier. Chaque cycle sauve last.pt avec
l'état complet (poids, optimiseur, générateurs aléatoires, compteur de convergence,
protocole) : après une interruption, relancer la même commande reprend la trajectoire
exacte qu'un entraînement ininterrompu aurait suivie, et une commande dont le jeu, la
graine, le λ ou la bande diffèrent est refusée.
Pour partir du modèle livré plutôt que de zéro (fine-tuning) :
python train/train.py --pool data/pool_full_v3.npy --init model/spear_best.pt
À savoir : même protocole, mêmes données, même graine redonnent le même entraînement ; de petites différences numériques restent possibles d'un matériel à l'autre (ordre des opérations flottantes sur GPU).
Les deux réseaux
SPEAR (src/.../models/spear.py) est une réimplémentation de l'auto-encodeur de
débruitage de l'article SPEAR (arXiv 2307.05339) : encodeur et décodeur symétriques de
4 blocs convolutifs 1D chacun, filtres 16/32/64/128, noyaux 32/64/128/320, sans
skip-connection, sortie sigmoïde dans [0,1]. 9,4 M de paramètres. La longueur
d'entrée est libre tant qu'elle est divisible par 16 ; le modèle livré travaille en
fenêtres de 1920 points (30 s à 64 Hz) et a été entraîné sur des fenêtres de
1600 points (les fenêtres DeepBeat, 25 s à 64 Hz).
Segade (src/.../models/segade.py) est le détecteur d'artefacts de Guo et al.
(segmentation point par point du signal en propre/artefact). Le checkpoint fourni a été
entraîné sur PPG DaLiA, le jeu public annoté en artefacts par des humains.
Protocole du modèle livré
Repris dans model/config.yaml, et vérifiable dans les métadonnées du checkpoint
lui-même (epoch, seed, lam, band, pool). Les paramètres sont solidaires :
changer l'un sans les autres change le comportement du système.
| paramètre | valeur |
|---|---|
| fréquence d'échantillonnage | 64 Hz |
| fenêtre de traitement | 30 s (1920 points) |
| jeu d'entraînement | pool_full_v3 : 234 999 fenêtres uniques, 109 participants, stratifié par participant, index exact fourni |
| prétraitement | recette Guo : passe-bande Butterworth ordre 2, 0,9-5 Hz, causal (sosfilt), puis min-max [0,1] |
| sélection du jeu | Segade seuil 0,5, fenêtres à 0 % d'artefact, doublons écartés |
| corruption d'entraînement | combinée : bruit (modèle RRest) + masquage, 10 augmentations par fenêtre |
| perte | RMSE + λ × erreur spectrale relative en bande 0,9-3 Hz, λ = 0,7 |
| optimiseur et arrêt | Adam, lr 1e-3, batch 128 ; arrêt par convergence (patience 5, seuil 0,0002) ; modèle livré = cycle 52 sur 55 |
| graine | 20260805 (réseau, ordre des lots, corruptions) |
| seuil Segade à l'inférence | 0,5, masque brut sans dilatation |
| rejet de fenêtre | plus de 75 % d'artefact |
| auto-conditionnement | fenêtre laissée telle quelle si moins de 3 % des intervalles battement à battement dévient de plus de 30 % de la médiane |
Vérifier l'intégrité des poids
27a7ea290fb76ded26cd3e319cbdcb60f2ce870eb2e698fa4b0b8cd60c88e999 model/spear_best.pt
fc6305ad2dd34241e60ece96f58df1265bcac3e4392dba75641b7504ad7407cd model/segade_fold0_best.pt
shasum -a 256 -c <<< "27a7ea290fb76ded26cd3e319cbdcb60f2ce870eb2e698fa4b0b8cd60c88e999 model/spear_best.pt"
Provenance et réutilisation
- Code SPEAR : réimplémenté pour le projet d'après l'article, avec deux ajouts
CALYPSO, signalés dans les docstrings : le terme de perte en bande cardiaque
(
training/losses.py) et l'auto-conditionnement à l'inférence (inference/denoise.py). - Code Segade : architecture et fonction de perte réimplémentées d'après le code publié
par les auteurs (repo
chengstark/Segade) ; le modèle de bruit d'entraînement reprend la boîte à outils RRest. - Poids : les deux checkpoints ont été entraînés dans le cadre du projet CALYPSO (2026) ; SPEAR sur le jeu DeepBeat décrit plus haut, Segade sur PPG DaLiA.
- Données : rien n'est redistribué ici. DeepBeat se télécharge depuis Synapse sous ses propres conditions d'utilisation. Ce dépôt est destiné à l'usage de l'équipe INTERACTIONS dans le cadre du projet CALYPSO.
Références
- SPEAR : Jain et al., A Self-Supervised Algorithm for Denoising Photoplethysmography Signals for Heart Rate Estimation from Wearables, arXiv 2307.05339 ; code des auteurs : pranay-jain/SPEAR-PPG-Denoiser.
- Segade : Guo et al., A supervised machine learning semantic segmentation approach for detecting artifacts in plethysmography signals from wearables, Physiological Measurement, 2021 ; code des auteurs : chengstark/Segade.
- Modèle de bruit : boîte à outils RRest de P. Charlton.
- Données d'entraînement : DeepBeat (Stanford), Synapse syn21985690 ; PPG DaLiA (Reiss et al., 2019) pour Segade.