Upgrade to Pro — share decks privately, control downloads, hide ads and more …

TSFR Edition #16 - Time Series et santé: datalogger médical 100hz, retour d'expérience après un an

TSFR Edition #16 - Time Series et santé: datalogger médical 100hz, retour d'expérience après un an

Pour cette 16ème édition, nous allons bénéficier d’un retour d’expérience d’utilisation de séries temporelles dans le domaine de la santé.

Le CHRU de Brest a décidé en 2020 d’acquérir la tension artérielle et la pression intracrânienne en continu de tous ses patients en réanimation, avec une résolution inégalée jusqu’ici. Découvrez cette aventure, de la conception à l’exploitation des 10 milliards de points résultant.

Pour nous raconter ce beau projet, nous aurons comme orateurs :

Pierre PAPIN : Électronicien passionné d’informatique, après 13 ans chez renault sport, je combine ces deux passions en un métier: développeur chez SenX. Quand un projet de collecte de données nécessite du hardware, je réalise la carte électronique, le soft embarqué, et toutes les couches nécessaires pour envoyer les données dans Warp 10. Armé de mon fer à souder et d’un stock de composants, j’ai participé au développement du respirateur open source Makair en mars 2020.

Arnaud MORE : Étudiant en dernière année de l’ENIB (École Nationale d’Ingénieur de Brest), école d’ingénieur généraliste, je réalise un parcours bi-diplomant en partenariat avec l’UBO afin de me spécialiser en traitement du signal. Actuellement en stage de fin d’études au CHRU de la cavale-blanche à Brest, j’aide les médecins à réaliser un outil d’aide à la décision. Ce stage me permet d’allier mes passions pour la médecine et l’ingénierie au sein d’un même projet.

TimeSeriesFr

June 07, 2022
Tweet

More Decks by TimeSeriesFr

Other Decks in Technology

Transcript

  1. Auteurs ▪ Pierre Papin Développeur hardware et software chez SenX

    ▪ Arnaud Moré Stagiaire ingénieur à l’ENIB, pour le CHRU 2
  2. L’idée Patients en réanimation chirurgicale La pression intracrânienne est le

    facteur important pouvant causer des lésions cérébrales irréversibles. La forme de la courbe reflète une pathologie. Idée : la forme des courbes de pression intracrânienne, déterminerait l’issue autant que la valeur absolue de la pression. 4
  3. Dataset cible Pour valider cette hypothèse, il faut un jeu

    de données : PIC, AP, enregistrés à 100Hz en continu. PtO2, température, enregistrés toutes les minutes. Caractéristiques du patient. Traitements administrés au patient. 5
  4. Mon rêve ! Utiliser un protocole médical ouvert, standard, permettant

    de streamer les données en temps réel ! HL7, poussé par Philips, est un protocole abominable permettant de transférer des waveforms. Il est possible de l’utiliser, mais il faut des mois de développement. Et les petits appareils ultra spécialisés pour la PIC et la PtO2 ne sont pas compatibles. 7
  5. La réalité PtO2 et température monitorés par Integra Licox. Cet

    appareil a une sortie USB prévue pour un module type FTDI (USB->RS232) La documentation du protocole est disponible. 8
  6. La réalité La PIC est monitorée par un Sophysa Pressio2

    Cet appareil a une sortie mini usb reconnue comme un port série par l’hôte. Le protocole est disponible. 9
  7. La réalité AP monitorée par un super moniteur Edwards Life

    Science. Il y a un port ethernet, mais rien de prévu pour streamer les données. Après activation de l’option, il y a une option pour exporter les données au format csv avec un point toutes les 5 secondes… 10
  8. Et à l’hôpital ? À l'hôpital, le poste de soin

    regroupe toutes les données patients des chambres du service. C’est une solution vendue par Philips, qui permet de visualiser à distance les courbes (basse résolution) des appareils Philips. Donc, au pied du lit, on connecte le plus d’appareils possible à une centrale Philips, par des liaisons… analogiques ! Philips peut aussi stocker les données… en blob binaire dans une base SQL. 11
  9. Deux liaisons séries et … Le moniteur Edwards Life Science

    dispose d’une seconde sortie analogique que je peux utiliser. Elle respecte le standard(*) médical, à savoir une jauge de contrainte émulée dont la sortie est calibrée à : 20,5µV /mmHg 12
  10. Solution AP Création d’un hardware spécifique pour convertir l’AP en

    un protocole série. 14 Acquisition de la pression artérielle, sortie sur un protocole série via un arduino nano. + Watchdog hardware pour le Rpi. RTC pour le raspberry
  11. Modélisation et données de santé Éviter de stocker des données

    de santé en zone HDS ! Séparer les données brutes des données confidentielles, en faisant le lien par un changement de patient : PIC, AP, enregistrés à 100Hz en continu. PtO2, température, enregistrés toutes les minutes. Caractéristiques du patient. Traitements administrés au patient. 18 time series, label = numéro de série du datalogger Confidentiel, reste géré par le CHRU
  12. Modélisation et données de santé PIC, AP, enregistrés à 100Hz

    en continu. PtO2, température, enregistrés toutes les minutes. Une GTS contenant un nom de patient aléatoire Le nom de patient aléatoire est noté dans les données cliniques. Caractéristiques du patient. Traitements administrés au patient. 19 time series, label = numéro de série du datalogger Confidentiel, reste géré par le CHRU
  13. Fonctionnalités annexes Un bouton “nouveau patient” crée un point dans

    une GTS (type STRING). Utilisation théorique : création d’un nouveau patient à chaque nouveau patient. En pratique : ça dépend si le médecin/infirmier est formé… Un bouton “soins en cours” crée un point dans une GTS (true). Utilisation théorique : l’infirmière appui sur le bouton avant de “remuer” le patient (ce qui perturbe fortement les courbes de pression) En pratique : … … parfois avant, parfois après, parfois jamais. 21
  14. Architecture 22 IHM Python + Kivy Collecte des liaisons série

    Java Warp 10 API api/v0/exec api/v0/exec 1 3 2 Warp 10 (SAAS) 4
  15. 1/ Collecte vers Warp 10 L’applicatif de collecte génère le

    WarpScript suivant: 23 <' 1654596856720463// AP{} 34.1 =1654596892170438// 35.2 =1654596892180438// 35.6 (...) '> @predict/storeData
  16. 2/ Affichage temps réel Pour chaque appareil, l’IHM python+kivy interroge

    une API: curl http://localhost:12345/api/LicoxPtO2/1/ # {"lastValue":0,"freshValue":true,"serialIsConnected":true} Pour ces requêtes régulières, pycurl préférable à request. 24
  17. 3/ Gestion du pseudo de patient L’IHM peut créer un

    patient, ou afficher le patient en cours, en interrogeant Warp 10 directement. r = requests.post(WARP10_ENDPOINT, data=""" @predict/currentPatient """, timeout=5) if (r.status_code == 200): lastPatient = r.json()[0] Pour plus de souplesse dans la gestion du code, utilisation d’une macro. 25
  18. 4/ Synchro SAAS Warp 10 : les endpoints sont exposés.

    Chaque datalogger écrit dans la base grâce à son token. 27
  19. 4/ Synchro SAAS, concrètement L’instance Warp 10 sur chaque datalogger,

    va essayer toutes les minutes de recopier les GTS locales vers l’instance Warp 10 SAAS. Un seul WarpScript suffit, placé dans /opt/warp10/warpscript/predict/60000/ 28
  20. 4/ Synchro SAAS, concrètement ▪ Chercher T = timestamp de

    la dernière synchronisation réussie (FETCH) ▪ Récupérer les GTS entre T et T + 8h (FETCH) ▪ Compresser et sérialiser les données (WRAP) ▪ Construire un WarpScript contenant les données sérialisées, le token d’ écriture, et les instructions pour décompresser et UPDATE les données ▪ Exécuter ce WarpScript sur l’instance Warp 10 distante (REXECZ) ▪ Si succès, écrire T+8h en valeur de la dernière synchro réussie (UPDATE) Pour tracer la dernière synchro réussie, utilisation d’une GTS nommée “upload”, par exemple. 29
  21. Disque et suppression des données Sur le datalogger, utilisation d’une

    carte SD industrielle donnée pour 30k cycle d’écriture. LevelDB est agressif pour les cartes SD. Les suppressions régulières entraînent des compactions durant lesquelles il faut réécrire beaucoup de fichiers. Solution : plugin “leveldb” de Warp 10. 30
  22. Disque et suppression des données Tous les jours, supprimer les

    données de plus de 30 jours. Un seul WarpScript suffit, placé dans /opt/warp10/warpscript/predict/86400000/ 30 d 'historylength' STORE NOW $historylength - 'deletestopTS' STORE 'read' @predict/localToken '~.*' {} $deletestopTS 100000 @senx/leveldb/purge L’utilisation du plugin “leveldb” permet de supprimer directement les fichiers .sst, sans nécessité d’attendre une compaction. 31 😄
  23. Performances en lecture en BDD 300 000 à 1 000

    000 de points par seconde Pour relire 10 milliards de points : ~5 heures Bien, mais largement perfectible, grâce aux HFiles ! 35
  24. HFiles ? Les History Files, ou HFiles, sont des conteneurs

    de stockage à très haute densité qui peuvent contenir des centaines de milliards de points de mesure provenant de millions de séries. ▪ Format spécifique Warp 10. ▪ Lecteur gratuit, générateur sous licence. ▪ Input format Spark inclus dans le lecteur. Le contenu de l’étude tient dans un fichier de 13go, soit 1.3 datapoints par octet (sans aucune altération). 36
  25. HFile, comment ça marche ? 37 { 'token' 'MyReadToken' 'selector'

    '~.*{}' 'end' NOW 'timespan' 100 d // encoder to encoder macro. cannot change class and labels here, but can COMPACT 'macro' <% {} ->GTS COMPACT %> 'path' 'file257' //'checksums' false // extra checksum for file for hdfs filesystem 'secret' 'myhfstoresecret' } HFDUMP La création des fichiers peut être automatisée depuis Warp 10.
  26. HFile, lecture 38 { 'store' 'predictraw' 'token' $hfToken 'class' '~.*'

    'labels' {} 'end' $end 'timespan' $timespan // 'count' 100 // you can limit 'lineage' 'hf' // add a "hf" attribute with list of hfiles the data come from } HFFETCH ->GTS HFFETCH peut être remplacé par FETCH. ~ 10 millions de points par seconde en lecture par thread, selon le hardware.
  27. Recommandation pour HFile Le fichier HFile va contenir un encodeur

    de possiblement 1 milliard de points pour la pression artérielle de chaque datalogger. Chaque lecture va donc nécessiter de charger l’encodeur entier et le décompresser. Il faut donc BEAUCOUP de ram si on fait un seul fichier HFile avec quelques GTS de 1 milliards de points. Pour Predict, on a choisi de découper en 1 HFile / jour (500 fichiers). 39 java.lang.OutOfMemoryError: Java heap space
  28. Config d’Arnaud Faute d’avoir un cluster hadoop au CHRU… Un

    laptop, 16go de RAM Warp 10 avec : - extension HFStore - plugin Jupyter Jupyter + python 40
  29. Exploration des données : temps d’exécution 47 Quelques chiffres :

    ▪ 1 seconde pour fetch 1 journée de data ( + 8 millions de points ) ▪ Profil matriciel assez lourd : ~20 secondes pour traiter 5 minutes de données, 12 threads en parallèle (~ 20 secondes par heure de data) ▪ Nettoyage de la PIC beaucoup plus rapide, quelques secondes par période de 5 minutes
  30. Analyse de forme de la courbe 49 Entraînement : 2500

    images classifiées : -2000 pour l’entraînement -250 de validation -250 de test Moins de 10 % d’erreurs Généralisation : Sur 7500 images prises aléatoirement 1: 547 2: 530 3: 198 4: 763 5: 544 6: 663 7: 494 8: 525 9: 996 10: 336 11: 1116 12: 902