SleePyPhases 0.2.1__tar.gz → 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/PKG-INFO +1 -1
  2. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/MultiScorer.py +8 -0
  3. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/Plugin.py +4 -5
  4. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/RecordFeatureExtraction.py +6 -71
  5. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/Eval.py +4 -10
  6. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/EvalReport.py +2 -3
  7. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/ExtractFeatures.py +6 -9
  8. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/Setup.py +5 -24
  9. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/Training.py +4 -0
  10. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases.egg-info/PKG-INFO +1 -1
  11. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases.egg-info/SOURCES.txt +0 -4
  12. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/setup.py +1 -1
  13. sleepyphases-0.2.1/SleePyPhases/FeatureExtraction copy.py +0 -116
  14. sleepyphases-0.2.1/SleePyPhases/recordloaders/MedicalDB.py +0 -124
  15. sleepyphases-0.2.1/SleePyPhases/recordloaders/RecordLoaderTSM.py +0 -34
  16. sleepyphases-0.2.1/tests/unit/__init__.py +0 -0
  17. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/LICENSE +0 -0
  18. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/README.md +0 -0
  19. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/DataManipulation.py +0 -0
  20. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/EventScorer.py +0 -0
  21. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/FeatureExtraction.py +0 -0
  22. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/PSGEventManager.py +0 -0
  23. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/Plot.py +0 -0
  24. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/PreManipulation.py +0 -0
  25. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/Reporter.py +0 -0
  26. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/SignalPreprocessing.py +0 -0
  27. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/SleepMetaData.py +0 -0
  28. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/__init__.py +0 -0
  29. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/BuildDataset.py +0 -0
  30. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/DataAnalysis.py +0 -0
  31. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/DataReport.py +0 -0
  32. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/EvalPlotExamples.py +0 -0
  33. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/ExportMetadataToMeticalDB.py +0 -0
  34. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/Extract.py +0 -0
  35. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/ExtractEvents.py +0 -0
  36. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/ExtractRecordFeatures.py +0 -0
  37. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/GatherMetadata.py +0 -0
  38. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/TestRun.py +0 -0
  39. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/ThresholdOptimisation.py +0 -0
  40. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/Validation.py +0 -0
  41. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/VisualizeConfig.py +0 -0
  42. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases/phases/__init__.py +0 -0
  43. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases.egg-info/dependency_links.txt +0 -0
  44. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases.egg-info/requires.txt +0 -0
  45. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/SleePyPhases.egg-info/top_level.txt +0 -0
  46. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/pyproject.toml +0 -0
  47. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/setup.cfg +0 -0
  48. {sleepyphases-0.2.1/SleePyPhases/recordloaders → sleepyphases-0.3.1/tests}/__init__.py +0 -0
  49. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/tests/conftest.py +0 -0
  50. {sleepyphases-0.2.1/tests → sleepyphases-0.3.1/tests/unit}/__init__.py +0 -0
  51. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/tests/unit/test_BuildDataset.py +0 -0
  52. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/tests/unit/test_BuildDatasetFolded.py +0 -0
  53. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/tests/unit/test_BuildDatasetSegments.py +0 -0
  54. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/tests/unit/test_DataManipulation.py +0 -0
  55. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/tests/unit/test_Eval.py +0 -0
  56. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/tests/unit/test_EventScorer.py +0 -0
  57. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/tests/unit/test_Extract.py +0 -0
  58. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/tests/unit/test_PreManipulation.py +0 -0
  59. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/tests/unit/test_RecordFeatureExtraction.py +0 -0
  60. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/tests/unit/test_RecordProcessor.py +0 -0
  61. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/tests/unit/test_Setup.py +0 -0
  62. {sleepyphases-0.2.1 → sleepyphases-0.3.1}/tests/unit/test_SignalPreprocessing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: SleePyPhases
3
- Version: 0.2.1
3
+ Version: 0.3.1
4
4
  Summary: A framwork for creating deep learning pipelines for sleep data
5
5
  Home-page: https://gitlab.com/sleep-is-all-you-need/sleepyphases
6
6
  Author: Franz Ehrlich
@@ -42,19 +42,27 @@ class MultiScorer(Scorer):
42
42
  if isinstance(predictions, list) or isinstance(predictions, tuple):
43
43
  p = predictions[i]
44
44
  elif predictions.shape[-1] == len(self.multiClassNums):
45
+ if len(predictions.shape) == 3:
46
+ predictions = predictions.reshape(-1, predictions.shape[-1])
45
47
  p = predictions[:, i]
46
48
  else:
47
49
  start = sum(self.multiClassNums[:i])
48
50
  end = start + self.multiClassNums[i]
51
+ if len(predictions.shape) == 3:
52
+ predictions = predictions.reshape(-1, predictions.shape[-1])
49
53
  p = predictions[:, start:end]
50
54
 
51
55
  if isinstance(truth, list) or isinstance(truth, tuple):
52
56
  t = truth[i]
53
57
  elif truth.shape[-1] == len(self.multiClassNums):
58
+ if len(truth.shape) == 3:
59
+ truth = truth.reshape(-1, truth.shape[-1])
54
60
  t = truth[:, i]
55
61
  else:
56
62
  start = sum(self.multiClassNums[:i])
57
63
  end = start + self.multiClassNums[i]
64
+ if len(truth.shape) == 3:
65
+ truth = truth.reshape(-1, truth.shape[-1])
58
66
  t = truth[:, start:end]
59
67
 
60
68
 
@@ -3,6 +3,7 @@ from pyPhasesRecordloader import RecordLoader
3
3
 
4
4
  from SleepHarmonizer.recordwriter.RecordWriter import RecordWriter
5
5
 
6
+ from SleePyPhases.phases.ExtractFeatures import ExtractFeatures
6
7
  from SleePyPhases.phases.Extract import Extract
7
8
  from SleePyPhases.phases.Setup import Setup
8
9
  from SleePyPhases.phases.BuildDataset import BuildDataset
@@ -12,6 +13,7 @@ from SleePyPhases.phases.Eval import Eval
12
13
  from SleePyPhases.phases.EvalReport import EvalReport
13
14
  from SleePyPhases.phases.ThresholdOptimisation import ThresholdOptimisation
14
15
  from SleePyPhases.phases.TestRun import TestRun
16
+ from SleePyPhases.phases.ExtractFeatures import ExtractFeatures
15
17
 
16
18
 
17
19
  from pyPhases.exporter.PickleExporter import PickleExporter
@@ -33,8 +35,8 @@ class Plugin(PluginAdapter):
33
35
  "ThresholdOptimisation": (ThresholdOptimisation, ["threshold", "validationResult"]),
34
36
  "Eval": (Eval, ["evalResults", "eventResults"]),
35
37
  "EvalReport": (EvalReport, []),
36
- "TestRun": (TestRun, [])
37
-
38
+ "ExtractFeatures": (ExtractFeatures, ["features"]),
39
+ "TestRun": (TestRun, []),
38
40
  }
39
41
  dataMap = {
40
42
  "features": ["metadata"],
@@ -69,8 +71,5 @@ class Plugin(PluginAdapter):
69
71
  project.registerExporter(ModelExporter({"basePath": dataPath}))
70
72
  project.registerExporter(MemmapRecordExporter({"basePath": dataPath}))
71
73
 
72
-
73
- def initPlugin(self):
74
- RecordLoader.registerRecordLoader("RecordLoaderTSM", "SleePyPhases.recordloaders")
75
74
 
76
75
 
@@ -1,17 +1,16 @@
1
- import pandas as pd
2
1
  from typing import List
3
2
 
4
3
  import numpy as np
4
+ import pandas as pd
5
5
  from pandas import DataFrame
6
+ from pyPhases import Swappable
6
7
  from pyPhasesML import FeatureExtraction as pyPhasesFeatureExtraction
7
- from pyPhasesRecordloader import RecordSignal, Signal, Event, ChannelsNotPresent
8
+ from pyPhasesRecordloader import ChannelsNotPresent, Event, RecordSignal, Signal
8
9
 
9
10
  from SleePyPhases.PSGEventManager import PSGEventManager
10
11
 
11
- class RecordFeatureExtraction(pyPhasesFeatureExtraction):
12
- """batchManipulation for the physionet challenge 2023
13
- segmentSignal: Recordsignal of the segment with 18 EEG channels
14
- """
12
+
13
+ class RecordFeatureExtraction(pyPhasesFeatureExtraction, Swappable):
15
14
 
16
15
  def step(self, stepname: str, recordSignal: RecordSignal, eventlist: List[Event], channel=None, **options) -> Signal:
17
16
  if hasattr(self, stepname):
@@ -271,68 +270,4 @@ class RecordFeatureExtraction(pyPhasesFeatureExtraction):
271
270
  # ret[f"cycle-{cycleNumber}-rem-duration"] = remTime
272
271
 
273
272
  return ret
274
-
275
- def spindles(self, segmentSignal: RecordSignal, eventlist: List[Event], channel: str):
276
- from .external.sumo.sumo.scripts.a7.butter_filter import butter_bandpass_filter, downsample
277
- # from .external.sumo.a7.detect_spindles import detect_spindle
278
- from .external.sumo.sumo.scripts.predict_plain_data import SimpleDataset
279
- # from .external.sumo.sumo.predict_plain_data import A7
280
- import pytorch_lightning as pl
281
- from torch.utils.data import Dataset, DataLoader
282
- import torch
283
- from .external.sumo.sumo.model.sumo import SUMO
284
- from .external.sumo.sumo.config.config import Config
285
- # from .external.sumo.model.data import spindle_vect_to_indices
286
-
287
- config = Config('predict', create_dirs=False)
288
-
289
- def get_model(p):
290
- # p = Path(p)
291
-
292
- model_checkpoint = torch.load(p)
293
-
294
- model = SUMO(config)
295
- model.load_state_dict(model_checkpoint['state_dict'])
296
-
297
- return model
298
-
299
- eegSignal = segmentSignal.getSignalByName(channel)
300
- resample_rate = 100
301
- model_path = "SleePyPhases/external/sumo/sumo/output/final.ckpt"
302
-
303
- if len(eegSignal.signal) == 0:
304
- return None
305
-
306
- eegs = []
307
- eegSignal = downsample(butter_bandpass_filter(eegSignal.signal, 0.3, 30.0, eegSignal.frequency, 10), eegSignal.frequency, resample_rate)
308
- eegs.append(eegSignal)
309
-
310
- dataset = SimpleDataset(eegs)
311
- dataloader = DataLoader(dataset)
312
- model = get_model(model_path)
313
- trainer = pl.Trainer(num_sanity_val_steps=0, logger=False)
314
- predictions = trainer.predict(model, dataloader)
315
- pred = predictions[0]
316
-
317
- # spindles_a7 = A7(x, resample_rate)
318
- spindle_vect = pred[0].numpy()
319
-
320
- diff = np.diff(np.r_[0, spindle_vect, 0]) # be able to detect spindles at the start and end of vector
321
- spindles = np.c_[np.argwhere(diff == 1), np.argwhere(diff == -1)] / resample_rate
322
- # spindles = spindle_vect_to_indices(spindle_vect) / resample_rate
323
-
324
-
325
- # frequencies, psd = signal.welch(eegs[0][s.start:s.end()],
326
- # fs=100,
327
- # nperseg=min(256, s.duration),
328
- # scaling='spectrum')
329
- # dominant_freq = frequencies[np.argmax(psd)]
330
-
331
- spindles = [Event("spindle", s[0], s[1] - s[0]) for s in spindles]
332
-
333
-
334
- return {
335
- "spindles-count": len(spindles),
336
- "spindles-mean-druation": np.array([s.duration for s in spindles]).mean()
337
- }
338
-
273
+
@@ -81,7 +81,7 @@ class Eval(Phase):
81
81
 
82
82
  # setup data and scorer
83
83
 
84
- classNums = self.getConfig("model.multiclassificationSize", [2])
84
+ classNums = self.getConfig("numClasses", [2])
85
85
  labelNames = self.getConfig("classification.labelNames")
86
86
  ignoreIndex = self.getConfig("classification.ignoreIndex", -1)
87
87
  metrics = self.getConfig("trainingParameter.validationMetrics")
@@ -99,16 +99,10 @@ class Eval(Phase):
99
99
 
100
100
  for data in tqdm(testData):
101
101
  x, truth = data
102
- # make sure to have a batchsize if batchSize == 1
103
- x = x.reshape(batchSize, x.shape[0], x.shape[1])
104
- truth = truth.reshape(batchSize, truth.shape[0], truth.shape[1])
105
102
 
106
- prediction = model.predict(x, get_likelihood=True, returnNumpy=False)
103
+ prediction = model.predict(x, returnNumpy=False)
107
104
  prediction, truth = da((prediction, truth))
108
105
 
109
- # prediction = prediction.reshape(-1, prediction.shape[2])
110
- # truth = truth.reshape(-1, truth.shape[2])
111
-
112
106
  scorer.score(truth, prediction, trace=True)
113
107
 
114
108
  result = scorer.scoreAllRecords()
@@ -152,7 +146,7 @@ class Eval(Phase):
152
146
  self.project.config.update(self.getConfig("eventEval", {}))
153
147
 
154
148
  evalMetrics = self.getConfig("eval.metrics")
155
- classNums = self.getConfig("model.multiclassificationSize", [2])
149
+ classNums = self.getConfig("numClasses", [2])
156
150
  labelNames = self.getConfig("classification.labelNames")
157
151
  predictionNames = self.getConfig("classification.predictionSignals")
158
152
  predictionFrequencies = self.getConfig("classification.predictionFrequencies")
@@ -193,7 +187,7 @@ class Eval(Phase):
193
187
  x = x.reshape([1] + list(x.shape))
194
188
  truth = truth.reshape([1] + list(truth.shape))
195
189
 
196
- prediction = model.predict(x, get_likelihood=True, returnNumpy=False)
190
+ prediction = model.predict(x, returnNumpy=False)
197
191
  prediction, truth = da((prediction, truth))
198
192
 
199
193
  # for labelIndex, labelName in enumerate(recordResults.keys()):
@@ -10,7 +10,6 @@ from pyPhasesRecordloader import RecordSignal, Signal
10
10
 
11
11
  from SleePyPhases import Plot
12
12
  from SleePyPhases.DataManipulation import DataManipulation
13
- from SleePyPhases.Reporter import Reporter
14
13
 
15
14
 
16
15
  class EvalReport(Phase):
@@ -244,8 +243,8 @@ class EvalReport(Phase):
244
243
  def copyRawData(self):
245
244
  modelConfigString = self.project.getDataFromName("modelState").getTagString()
246
245
  trainingLogPath = f"logs/{modelConfigString}/"
247
- shutil.copyfile(trainingLogPath + "log.csv", Reporter.basePath + "training.log")
248
- shutil.copyfile(trainingLogPath + "project.config", Reporter.basePath + "project.json")
246
+ shutil.copyfile(trainingLogPath + "log.csv", self.evalPath + "training.log")
247
+ shutil.copyfile(trainingLogPath + "project.config", self.evalPath + "project.json")
249
248
 
250
249
  def trainingPlot(self, logFile):
251
250
  import matplotlib.pyplot as plt
@@ -76,7 +76,7 @@ class ExtractFeatures(Phase):
76
76
  try:
77
77
  recordSignal = recordLoader.getHarmonizedSignal(recordId)
78
78
 
79
- events: List[Event] = RecordFeatureExtraction(self.project).step(name, recordSignal, *options)
79
+ events: List[Event] = RecordFeatureExtraction.getInstance().step(name, recordSignal, *options)
80
80
 
81
81
  if channelType is not None:
82
82
  channelType = [s.name for s in recordSignal.signals if s.typeStr == channelType]
@@ -192,7 +192,7 @@ class ExtractFeatures(Phase):
192
192
  try:
193
193
  idx = (recordId, c)
194
194
  featureStep = featureConfig["type"]
195
- RecordFeatureExtraction(self.project).updateMetadataByStep(featureStep, recordSignal, eventlist, metadata=self.features, channel=c)
195
+ RecordFeatureExtraction.getInstance().updateMetadataByStep(featureStep, recordSignal, eventlist, metadata=self.features, channel=c)
196
196
  except ChannelsNotPresent as e:
197
197
  self.logError(f"channels not present: {e.channels}")
198
198
 
@@ -209,18 +209,15 @@ class ExtractFeatures(Phase):
209
209
  self.features = None
210
210
  metadata = self.project.getData("metadata", pd.DataFrame)
211
211
  recordIds = metadata["recordId"]
212
+ forceCalculation = self.getConfig("featureExtraction.features", True)
212
213
 
213
214
  reqFeatures = {f["name"]: True for f in self.getConfig("featureExtraction.features", [])}
214
215
 
215
- # groupedRecords = {"pid_202436073": "acq_237478592"}
216
216
  for recordId in tqdm(recordIds.iloc):
217
- # tryToGenerate has no meaning, it is just known to be not in the metadata, so the record will always be recalculated
218
- # self.getData("features", pd.DataFrame, recordId=recordId, tryToGenerate=True, **reqFeatures)
217
+ if forceCalculation:
218
+ # the parameter forced has no meaning, it is just known to be not in the metadata, so the record will always be recalculated
219
+ reqFeatures["forced"] = True # should never be found
219
220
  rows = self.getData("features", pd.DataFrame, recordId=recordId, **reqFeatures)
220
221
  if len(rows) == 0:
221
222
  self.logError(f"no features for {recordId}")
222
223
 
223
-
224
- # get a single feature:
225
- # feat = {"swa": True}
226
- # x = self.getData("features", pd.DataFrame, recordId="shhs1-200002", channel="EEG", **feat)
@@ -4,36 +4,20 @@ from pyPhases import Phase
4
4
  from pyPhasesML import DataversionManager, Scorer
5
5
  from pyPhasesRecordloader import RecordLoader
6
6
 
7
- from SleePyPhases.recordloaders.MedicalDB import MedicalDB
8
7
 
9
8
 
10
9
  class Setup(Phase):
11
10
  def prepareConfig(self):
12
- numLabels = len(self.getConfig("classification.labelNames"))
11
+ numLabels = len(self.getConfig("classification.labelNames", []))
13
12
  self.setConfig("numLabels", numLabels)
14
13
 
15
- numClasses = [len(c) for c in self.getConfig("classification.classNames")]
14
+ numClasses = [len(c) for c in self.getConfig("classification.classNames", [])]
16
15
  self.setConfig("numClasses", numClasses)
17
16
 
18
- defaultValidationbatchManipulation = self.getConfig("segmentManipulationEval", self.getConfig("segmentManipulation"))
17
+ defaultValidationbatchManipulation = self.getConfig("segmentManipulationEval", self.getConfig("segmentManipulation", []))
19
18
  self.setConfig("segmentManipulationEval", defaultValidationbatchManipulation)
20
-
21
- # alice loader
22
- RecordLoader.registerRecordLoader("RecordLoaderTest", "SleePyPhases.recordloaders")
23
- RecordLoader.registerRecordLoader("RecordLoaderTSM", "SleePyPhases.recordloaders")
24
- tsmPath = self.getConfig("tsm-path", False)
25
- if tsmPath is not False:
26
- tsmPath = Path(tsmPath)
27
- self.project.setConfig("loader.tsm.filePath", tsmPath.as_posix())
28
- self.project.setConfig("loader.tsm.dataset.downloader.basePath", tsmPath.as_posix())
29
-
30
- tsmPath = self.getConfig("tsm-domino-path", False)
31
- if tsmPath is not False:
32
- tsmPath = Path(tsmPath)
33
- self.project.setConfig("loader.tsm-domino.filePath", tsmPath.as_posix())
34
- self.project.setConfig("loader.tsm-domino.dataset.downloader.basePath", tsmPath.as_posix())
35
-
36
- preprocessingConfig = self.getConfig("preprocessing")
19
+
20
+ preprocessingConfig = self.getConfig("preprocessing", {})
37
21
  if "combineChannels" in preprocessingConfig:
38
22
  RecordLoader.get().addCombinedChannels(preprocessingConfig["combineChannels"])
39
23
 
@@ -62,9 +46,6 @@ class Setup(Phase):
62
46
  return kappa
63
47
  Scorer.registerMetric("reduceAndKappa", reduceKappa, combineReduceKappa)
64
48
 
65
- MedicalDB.config = self.getConfig("medicalDB", {})
66
-
67
-
68
49
  def getDataVersionManager(self):
69
50
  groupedRecords = self.project.getData("allDBRecordIds", list)
70
51
  seed = self.getConfig("dataversion.seed", None)
@@ -77,6 +77,8 @@ class Training(Phase):
77
77
 
78
78
  gridOutputs = []
79
79
  for fold in range(startfold, endfold):
80
+ # save model state (random initialisation or pretrained)
81
+ startState = ModelManager.getModel().model.state_dict()
80
82
  self.setConfig("fold", fold)
81
83
  # only train if it doesnt allready exist
82
84
  self.getData("modelState", Model)
@@ -85,6 +87,8 @@ class Training(Phase):
85
87
  self.project.unregister("modelState")
86
88
  self.project.unregister("modelStateConfig")
87
89
  gridOutputs.append(self.gridOutput)
90
+ # reset model state
91
+ ModelManager.getModel().model.load_state_dict(startState)
88
92
 
89
93
  self.project.gridOutput = {
90
94
  "epochs": str(np.mean([m["epochs"] for m in gridOutputs])),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: SleePyPhases
3
- Version: 0.2.1
3
+ Version: 0.3.1
4
4
  Summary: A framwork for creating deep learning pipelines for sleep data
5
5
  Home-page: https://gitlab.com/sleep-is-all-you-need/sleepyphases
6
6
  Author: Franz Ehrlich
@@ -4,7 +4,6 @@ pyproject.toml
4
4
  setup.py
5
5
  SleePyPhases/DataManipulation.py
6
6
  SleePyPhases/EventScorer.py
7
- SleePyPhases/FeatureExtraction copy.py
8
7
  SleePyPhases/FeatureExtraction.py
9
8
  SleePyPhases/MultiScorer.py
10
9
  SleePyPhases/PSGEventManager.py
@@ -40,9 +39,6 @@ SleePyPhases/phases/Training.py
40
39
  SleePyPhases/phases/Validation.py
41
40
  SleePyPhases/phases/VisualizeConfig.py
42
41
  SleePyPhases/phases/__init__.py
43
- SleePyPhases/recordloaders/MedicalDB.py
44
- SleePyPhases/recordloaders/RecordLoaderTSM.py
45
- SleePyPhases/recordloaders/__init__.py
46
42
  tests/__init__.py
47
43
  tests/conftest.py
48
44
  tests/unit/__init__.py
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="SleePyPhases",
8
- version="v0.2.1"[1:],
8
+ version="v0.3.1"[1:],
9
9
  author="Franz Ehrlich",
10
10
  author_email="fehrlichd@gmail.com",
11
11
  description="A framwork for creating deep learning pipelines for sleep data",
@@ -1,116 +0,0 @@
1
- from typing import List
2
-
3
- import numpy as np
4
- from pyPhasesML import FeatureExtraction as pyPhasesFeatureExtraction
5
- from pyPhasesML import ModelManager
6
- from pyPhasesRecordloader import RecordSignal, Event
7
-
8
- from .DataAugmentation import DataAugmentation
9
-
10
-
11
- class FeatureExtraction(pyPhasesFeatureExtraction):
12
- """augmentation for the physionet challenge 2023
13
- segmentSignal: Recordsignal of the segment with 18 EEG channels
14
- """
15
-
16
- def __init__(self, project) -> None:
17
- super().__init__()
18
- self.project = project
19
-
20
- def time(self, segmentSignal: RecordSignal):
21
- segmentLength = segmentSignal.getShape()[1]
22
- # segmentLengthInHOurs = segmentLength / segmentSignal.targetFrequency / 3600
23
- # hour, minutes = segmentSignal.start.split(":")
24
- # startTimeInHours = int(hour) + int(minutes) / 60
25
- # endTimeInHours = startTimeInHours + segmentLengthInHOurs
26
- hour = segmentSignal.start
27
- endTimeInHours = hour + 1
28
- return np.linspace(hour, endTimeInHours, segmentLength)
29
-
30
- def featureModel(self, segmentSignal: RecordSignal, featureName: str, xChannels: List[str]):
31
- import torch
32
- useGPU = torch.cuda.is_available() and False
33
- with self.project:
34
- config = self.project.config["featureConfigs", featureName]
35
- self.project.config.update(config)
36
- self.project.addConfig(config)
37
-
38
- self.project.trigger("configChanged", None)
39
- self.project.setConfig("trainingParameter.batchSize", 1)
40
- self.project.setConfig("recordWise", True)
41
-
42
- modelPath = self.project.getConfig("featureModel", torch)
43
-
44
- # this is needed for mutlithreading
45
- ModelManager.loadModel(self.project)
46
- # get feature model
47
- model = ModelManager.getModel(True)
48
- model.useGPU = useGPU
49
- state = model.load(modelPath)
50
- model.loadState(state)
51
- featureModel = model.model.eval()
52
-
53
- featureModel = featureModel.cuda() if useGPU else featureModel.cpu()
54
-
55
- # we assum that the segment is already preprocessed for the model
56
- array = segmentSignal.getSignalArray(xChannels, transpose=True)
57
-
58
- da = DataAugmentation(self.project.config, self.project.getConfig("datasetSplit"), recordAnnotations={})
59
- array, _ = da.augmentSegment(array, None)
60
- array = array.transpose(2, 1, 0)
61
-
62
- features = model.predict(array, get_likelihood=True)
63
- _, features = da.restoreLength(None, features, length=segmentSignal.getShape()[1])
64
- features = features[:, :, 1]
65
-
66
- return features
67
-
68
- def spindles(self, segmentSignal: RecordSignal): #xChannels: List[str]
69
- from .external.sumo.a7.butter_filter import butter_bandpass_filter, downsample
70
- # from .external.sumo.a7.detect_spindles import detect_spindle
71
- from .external.sumo.predict_plain_data import SimpleDataset
72
- from .external.sumo.predict_plain_data import A7
73
- import pytorch_lightning as pl
74
- from torch.utils.data import Dataset, DataLoader
75
- import torch
76
- from .external.sumo.model.sumo import SUMO
77
- from .external.sumo.model.config import Config
78
- # from .external.sumo.model.data import spindle_vect_to_indices
79
-
80
- config = Config('predict', create_dirs=False)
81
-
82
- def get_model(p):
83
- # p = Path(p)
84
-
85
- model_checkpoint = torch.load(p)
86
-
87
- model = SUMO(config)
88
- model.load_state_dict(model_checkpoint['state_dict'])
89
-
90
- return model
91
-
92
- eegSignals = [s for s in segmentSignal.signals if s.typeStr == "eeg"]
93
- resample_rate = 100
94
- model_path = "SleePyPhases/external/sumo/model/final.ckpt"
95
-
96
- eegs = []
97
- for eegSignal in eegSignals:
98
- eegSignal = downsample(butter_bandpass_filter(eegSignal.signal, 0.3, 30.0, eegSignal.frequency, 10), eegSignal.frequency, resample_rate)
99
- eegs.append(eegSignal)
100
-
101
- dataset = SimpleDataset(eegs)
102
- dataloader = DataLoader(dataset)
103
- model = get_model(model_path)
104
- trainer = pl.Trainer(num_sanity_val_steps=0, logger=False)
105
- predictions = trainer.predict(model, dataloader)
106
-
107
- for x, pred in zip(eegs, predictions):
108
- # spindles_a7 = A7(x, resample_rate)
109
- spindle_vect = pred[0].numpy()
110
-
111
- diff = np.diff(np.r_[0, spindle_vect, 0]) # be able to detect spindles at the start and end of vector
112
- spindles = np.c_[np.argwhere(diff == 1), np.argwhere(diff == -1)] / resample_rate
113
- # spindles = spindle_vect_to_indices(spindle_vect) / resample_rate
114
-
115
-
116
- return [Event("spindle-slow", 500, 10)]
@@ -1,124 +0,0 @@
1
- import sys
2
-
3
- from pyPhases.util.Logger import classLogger
4
- from pypika import Table, PostgreSQLQuery as Query
5
- from pypika.queries import QueryBuilder
6
-
7
-
8
- @classLogger
9
- class MedicalDB:
10
- connection = None
11
- client = None
12
- assocCursor = None
13
- _instance = None
14
-
15
- config = {
16
- "user": "root",
17
- "password": "example",
18
- "host": "localhost",
19
- "port": 5432,
20
- "database": "data",
21
- }
22
-
23
- @classmethod
24
- def get(cls) -> "MedicalDB":
25
- if cls._instance is None:
26
- cls._instance = cls.__new__(cls)
27
- cls._instance.connect()
28
- return cls._instance
29
-
30
- def connect(self):
31
-
32
- import psycopg2
33
-
34
- try:
35
- c = MedicalDB.config
36
- conn = psycopg2.connect(
37
- "host=%s port=%i dbname=%s user=%s password=%s"
38
- % (
39
- c["host"],
40
- c["port"],
41
- c["database"],
42
- c["user"],
43
- c["password"],
44
- )
45
- )
46
-
47
- except psycopg2.Error as e:
48
- self.logError(f"Error connecting to Postgres Platform: {e}")
49
- sys.exit(1)
50
- self.conn = conn
51
- self.cursor = conn.cursor()
52
-
53
- def execute(self, sql, **vars):
54
- if isinstance(sql, QueryBuilder):
55
- sql = sql.get_sql()
56
- return self.cursor.execute(sql, **vars)
57
-
58
- def executeAndFetch(self, sql, **vars):
59
- self.execute(sql, **vars)
60
- return self.cursor.fetchall()
61
-
62
- def commit(self):
63
- self.conn.commit()
64
-
65
- def executeAndFetchOne(self, sql, **vars):
66
- self.execute(sql, **vars)
67
- return self.cursor.fetchone()
68
-
69
- def close(self):
70
- if self.connection is not None:
71
- self.connection.close()
72
-
73
- def fillRecordId(self, id):
74
- return id
75
-
76
- def getRecordData(self, recordId):
77
- record = Table("record", schema=self.config["schema"])
78
- patient = Table("patient", schema=self.config["schema"])
79
- medCase = Table("medical_case", schema=self.config["schema"])
80
- q = (
81
- Query.from_(record)
82
- .select(patient.id_patient, record.id_medical_case, record.start, patient.date_of_birth, patient.gender)
83
- .join(medCase).on(record.id_medical_case == medCase.id_medical_case)
84
- .join(patient).on(patient.id_patient == medCase.id_patient)
85
- .where(record.id_record == recordId)
86
- )
87
- row = self.executeAndFetchOne(q)
88
-
89
- if row is None:
90
- return None
91
-
92
- row = list(row)
93
- age = None if row[2] or row[3] is None else row[2] - row[3]
94
- row[3] = age
95
-
96
- return row
97
-
98
- def getDiagnoses(self, recordId):
99
- diag = Table("diagnosis", schema=self.config["schema"])
100
- record = Table("record", schema=self.config["schema"])
101
- medCase = Table("medical_case", schema=self.config["schema"])
102
- q = Query.from_(diag)\
103
- .select("diagnosis_category_id", "diagnosis")\
104
- .join(medCase).on(diag.id_medical_case == medCase.id_medical_case)\
105
- .join(record).on(medCase.id_medical_case == record.id_medical_case)\
106
- .where(record.id_record == recordId)\
107
- .get_sql()
108
-
109
- diagnoses = self.executeAndFetch(q)
110
-
111
- diagnoseCats = {d[0]: d[1] for d in diagnoses}
112
- return diagnoseCats
113
-
114
- def getPSGType(self, recordId):
115
-
116
- record = Table("record", schema=self.config["schema"])
117
- q = (
118
- Query.from_(record)
119
- .select("psg_config")
120
- .where(record.id_record == recordId)
121
- )
122
- r = self.executeAndFetchOne(q)
123
-
124
- return r[0] if bool(r) else ""
@@ -1,34 +0,0 @@
1
- from SleePyPhases.recordloaders.MedicalDB import MedicalDB
2
- from SleepHarmonizer import RecordLoaderAlice
3
-
4
-
5
- class RecordLoaderTSM(RecordLoaderAlice):
6
- config = {}
7
-
8
- def getMetaData(self, recordName):
9
- metadata = super().getMetaData(recordName)
10
- del metadata["patientName"]
11
- del metadata["patientCode"]
12
- del metadata["patientAdd"]
13
- del metadata["technician"]
14
-
15
- db = MedicalDB.get()
16
- row = db.getRecordData(recordName)
17
- diagnoses = db.getDiagnoses(recordName)
18
- metadata["psg_type"] = db.getPSGType(recordName)
19
-
20
- if row is not None:
21
- patient_id, case_id, recordDate, patientAge, gender = row
22
-
23
- metadata["patient"] = patient_id
24
- metadata["case"] = case_id
25
- metadata["age"] = patientAge
26
- metadata["gender"] = gender
27
- metadata["startRecord"] = recordDate
28
-
29
- if diagnoses is not None:
30
- metadata.update(diagnoses)
31
-
32
- db.close()
33
-
34
- return metadata
File without changes
File without changes
File without changes
File without changes