rapidtide 2.9.5__py3-none-any.whl → 3.1.3__py3-none-any.whl

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 (405) hide show
  1. cloud/gmscalc-HCPYA +1 -1
  2. cloud/mount-and-run +2 -0
  3. cloud/rapidtide-HCPYA +3 -3
  4. rapidtide/Colortables.py +538 -38
  5. rapidtide/OrthoImageItem.py +1094 -51
  6. rapidtide/RapidtideDataset.py +1709 -114
  7. rapidtide/__init__.py +0 -8
  8. rapidtide/_version.py +4 -4
  9. rapidtide/calccoherence.py +242 -97
  10. rapidtide/calcnullsimfunc.py +240 -140
  11. rapidtide/calcsimfunc.py +314 -129
  12. rapidtide/correlate.py +1211 -389
  13. rapidtide/data/examples/src/testLD +56 -0
  14. rapidtide/data/examples/src/test_findmaxlag.py +2 -2
  15. rapidtide/data/examples/src/test_mlregressallt.py +32 -17
  16. rapidtide/data/examples/src/testalign +1 -1
  17. rapidtide/data/examples/src/testatlasaverage +35 -7
  18. rapidtide/data/examples/src/testboth +21 -0
  19. rapidtide/data/examples/src/testcifti +11 -0
  20. rapidtide/data/examples/src/testdelayvar +13 -0
  21. rapidtide/data/examples/src/testdlfilt +25 -0
  22. rapidtide/data/examples/src/testfft +35 -0
  23. rapidtide/data/examples/src/testfileorfloat +37 -0
  24. rapidtide/data/examples/src/testfmri +94 -27
  25. rapidtide/data/examples/src/testfuncs +3 -3
  26. rapidtide/data/examples/src/testglmfilt +8 -6
  27. rapidtide/data/examples/src/testhappy +84 -51
  28. rapidtide/data/examples/src/testinitdelay +19 -0
  29. rapidtide/data/examples/src/testmodels +33 -0
  30. rapidtide/data/examples/src/testnewrefine +26 -0
  31. rapidtide/data/examples/src/testnoiseamp +21 -0
  32. rapidtide/data/examples/src/testppgproc +17 -0
  33. rapidtide/data/examples/src/testrefineonly +22 -0
  34. rapidtide/data/examples/src/testretro +26 -13
  35. rapidtide/data/examples/src/testretrolagtcs +16 -0
  36. rapidtide/data/examples/src/testrolloff +11 -0
  37. rapidtide/data/examples/src/testsimdata +45 -28
  38. rapidtide/data/models/model_cnn_pytorch/loss.png +0 -0
  39. rapidtide/data/models/model_cnn_pytorch/loss.txt +1 -0
  40. rapidtide/data/models/model_cnn_pytorch/model.pth +0 -0
  41. rapidtide/data/models/model_cnn_pytorch/model_meta.json +68 -0
  42. rapidtide/data/models/model_cnn_pytorch_fulldata/loss.png +0 -0
  43. rapidtide/data/models/model_cnn_pytorch_fulldata/loss.txt +1 -0
  44. rapidtide/data/models/model_cnn_pytorch_fulldata/model.pth +0 -0
  45. rapidtide/data/models/model_cnn_pytorch_fulldata/model_meta.json +80 -0
  46. rapidtide/data/models/model_cnnbp_pytorch_fullldata/loss.png +0 -0
  47. rapidtide/data/models/model_cnnbp_pytorch_fullldata/loss.txt +1 -0
  48. rapidtide/data/models/model_cnnbp_pytorch_fullldata/model.pth +0 -0
  49. rapidtide/data/models/model_cnnbp_pytorch_fullldata/model_meta.json +138 -0
  50. rapidtide/data/models/model_cnnfft_pytorch_fulldata/loss.png +0 -0
  51. rapidtide/data/models/model_cnnfft_pytorch_fulldata/loss.txt +1 -0
  52. rapidtide/data/models/model_cnnfft_pytorch_fulldata/model.pth +0 -0
  53. rapidtide/data/models/model_cnnfft_pytorch_fulldata/model_meta.json +128 -0
  54. rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/loss.png +0 -0
  55. rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/loss.txt +1 -0
  56. rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/model.pth +0 -0
  57. rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/model_meta.json +49 -0
  58. rapidtide/data/models/model_revised_tf2/model.keras +0 -0
  59. rapidtide/data/models/{model_serdar → model_revised_tf2}/model_meta.json +1 -1
  60. rapidtide/data/models/model_serdar2_tf2/model.keras +0 -0
  61. rapidtide/data/models/{model_serdar2 → model_serdar2_tf2}/model_meta.json +1 -1
  62. rapidtide/data/models/model_serdar_tf2/model.keras +0 -0
  63. rapidtide/data/models/{model_revised → model_serdar_tf2}/model_meta.json +1 -1
  64. rapidtide/data/reference/HCP1200v2_MTT_2mm.nii.gz +0 -0
  65. rapidtide/data/reference/HCP1200v2_binmask_2mm.nii.gz +0 -0
  66. rapidtide/data/reference/HCP1200v2_csf_2mm.nii.gz +0 -0
  67. rapidtide/data/reference/HCP1200v2_gray_2mm.nii.gz +0 -0
  68. rapidtide/data/reference/HCP1200v2_graylaghist.json +7 -0
  69. rapidtide/data/reference/HCP1200v2_graylaghist.tsv.gz +0 -0
  70. rapidtide/data/reference/HCP1200v2_laghist.json +7 -0
  71. rapidtide/data/reference/HCP1200v2_laghist.tsv.gz +0 -0
  72. rapidtide/data/reference/HCP1200v2_mask_2mm.nii.gz +0 -0
  73. rapidtide/data/reference/HCP1200v2_maxcorr_2mm.nii.gz +0 -0
  74. rapidtide/data/reference/HCP1200v2_maxtime_2mm.nii.gz +0 -0
  75. rapidtide/data/reference/HCP1200v2_maxwidth_2mm.nii.gz +0 -0
  76. rapidtide/data/reference/HCP1200v2_negmask_2mm.nii.gz +0 -0
  77. rapidtide/data/reference/HCP1200v2_timepercentile_2mm.nii.gz +0 -0
  78. rapidtide/data/reference/HCP1200v2_white_2mm.nii.gz +0 -0
  79. rapidtide/data/reference/HCP1200v2_whitelaghist.json +7 -0
  80. rapidtide/data/reference/HCP1200v2_whitelaghist.tsv.gz +0 -0
  81. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2.xml +131 -0
  82. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2_regions.txt +60 -0
  83. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2_space-MNI152NLin6Asym_2mm.nii.gz +0 -0
  84. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm.nii.gz +0 -0
  85. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm_mask.nii.gz +0 -0
  86. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin6Asym_2mm_mask.nii.gz +0 -0
  87. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL2_space-MNI152NLin6Asym_2mm_mask.nii.gz +0 -0
  88. rapidtide/data/reference/MNI152_T1_1mm_Brain_FAST_seg.nii.gz +0 -0
  89. rapidtide/data/reference/MNI152_T1_1mm_Brain_Mask.nii.gz +0 -0
  90. rapidtide/data/reference/MNI152_T1_2mm_Brain_FAST_seg.nii.gz +0 -0
  91. rapidtide/data/reference/MNI152_T1_2mm_Brain_Mask.nii.gz +0 -0
  92. rapidtide/decorators.py +91 -0
  93. rapidtide/dlfilter.py +2553 -414
  94. rapidtide/dlfiltertorch.py +5201 -0
  95. rapidtide/externaltools.py +328 -13
  96. rapidtide/fMRIData_class.py +178 -0
  97. rapidtide/ffttools.py +168 -0
  98. rapidtide/filter.py +2704 -1462
  99. rapidtide/fit.py +2361 -579
  100. rapidtide/genericmultiproc.py +197 -0
  101. rapidtide/happy_supportfuncs.py +3255 -548
  102. rapidtide/helper_classes.py +590 -1181
  103. rapidtide/io.py +2569 -468
  104. rapidtide/linfitfiltpass.py +784 -0
  105. rapidtide/makelaggedtcs.py +267 -97
  106. rapidtide/maskutil.py +555 -25
  107. rapidtide/miscmath.py +867 -137
  108. rapidtide/multiproc.py +217 -44
  109. rapidtide/patchmatch.py +752 -0
  110. rapidtide/peakeval.py +32 -32
  111. rapidtide/ppgproc.py +2205 -0
  112. rapidtide/qualitycheck.py +353 -40
  113. rapidtide/refinedelay.py +854 -0
  114. rapidtide/refineregressor.py +939 -0
  115. rapidtide/resample.py +725 -204
  116. rapidtide/scripts/__init__.py +1 -0
  117. rapidtide/scripts/{adjustoffset → adjustoffset.py} +7 -2
  118. rapidtide/scripts/{aligntcs → aligntcs.py} +7 -2
  119. rapidtide/scripts/{applydlfilter → applydlfilter.py} +7 -2
  120. rapidtide/scripts/applyppgproc.py +28 -0
  121. rapidtide/scripts/{atlasaverage → atlasaverage.py} +7 -2
  122. rapidtide/scripts/{atlastool → atlastool.py} +7 -2
  123. rapidtide/scripts/{calcicc → calcicc.py} +7 -2
  124. rapidtide/scripts/{calctexticc → calctexticc.py} +7 -2
  125. rapidtide/scripts/{calcttest → calcttest.py} +7 -2
  126. rapidtide/scripts/{ccorrica → ccorrica.py} +7 -2
  127. rapidtide/scripts/delayvar.py +28 -0
  128. rapidtide/scripts/{diffrois → diffrois.py} +7 -2
  129. rapidtide/scripts/{endtidalproc → endtidalproc.py} +7 -2
  130. rapidtide/scripts/{fdica → fdica.py} +7 -2
  131. rapidtide/scripts/{filtnifti → filtnifti.py} +7 -2
  132. rapidtide/scripts/{filttc → filttc.py} +7 -2
  133. rapidtide/scripts/{fingerprint → fingerprint.py} +20 -16
  134. rapidtide/scripts/{fixtr → fixtr.py} +7 -2
  135. rapidtide/scripts/{gmscalc → gmscalc.py} +7 -2
  136. rapidtide/scripts/{happy → happy.py} +7 -2
  137. rapidtide/scripts/{happy2std → happy2std.py} +7 -2
  138. rapidtide/scripts/{happywarp → happywarp.py} +8 -4
  139. rapidtide/scripts/{histnifti → histnifti.py} +7 -2
  140. rapidtide/scripts/{histtc → histtc.py} +7 -2
  141. rapidtide/scripts/{glmfilt → linfitfilt.py} +7 -4
  142. rapidtide/scripts/{localflow → localflow.py} +7 -2
  143. rapidtide/scripts/{mergequality → mergequality.py} +7 -2
  144. rapidtide/scripts/{pairproc → pairproc.py} +7 -2
  145. rapidtide/scripts/{pairwisemergenifti → pairwisemergenifti.py} +7 -2
  146. rapidtide/scripts/{physiofreq → physiofreq.py} +7 -2
  147. rapidtide/scripts/{pixelcomp → pixelcomp.py} +7 -2
  148. rapidtide/scripts/{plethquality → plethquality.py} +7 -2
  149. rapidtide/scripts/{polyfitim → polyfitim.py} +7 -2
  150. rapidtide/scripts/{proj2flow → proj2flow.py} +7 -2
  151. rapidtide/scripts/{rankimage → rankimage.py} +7 -2
  152. rapidtide/scripts/{rapidtide → rapidtide.py} +7 -2
  153. rapidtide/scripts/{rapidtide2std → rapidtide2std.py} +7 -2
  154. rapidtide/scripts/{resamplenifti → resamplenifti.py} +7 -2
  155. rapidtide/scripts/{resampletc → resampletc.py} +7 -2
  156. rapidtide/scripts/retrolagtcs.py +28 -0
  157. rapidtide/scripts/retroregress.py +28 -0
  158. rapidtide/scripts/{roisummarize → roisummarize.py} +7 -2
  159. rapidtide/scripts/{runqualitycheck → runqualitycheck.py} +7 -2
  160. rapidtide/scripts/{showarbcorr → showarbcorr.py} +7 -2
  161. rapidtide/scripts/{showhist → showhist.py} +7 -2
  162. rapidtide/scripts/{showstxcorr → showstxcorr.py} +7 -2
  163. rapidtide/scripts/{showtc → showtc.py} +7 -2
  164. rapidtide/scripts/{showxcorr_legacy → showxcorr_legacy.py} +8 -8
  165. rapidtide/scripts/{showxcorrx → showxcorrx.py} +7 -2
  166. rapidtide/scripts/{showxy → showxy.py} +7 -2
  167. rapidtide/scripts/{simdata → simdata.py} +7 -2
  168. rapidtide/scripts/{spatialdecomp → spatialdecomp.py} +7 -2
  169. rapidtide/scripts/{spatialfit → spatialfit.py} +7 -2
  170. rapidtide/scripts/{spatialmi → spatialmi.py} +7 -2
  171. rapidtide/scripts/{spectrogram → spectrogram.py} +7 -2
  172. rapidtide/scripts/stupidramtricks.py +238 -0
  173. rapidtide/scripts/{synthASL → synthASL.py} +7 -2
  174. rapidtide/scripts/{tcfrom2col → tcfrom2col.py} +7 -2
  175. rapidtide/scripts/{tcfrom3col → tcfrom3col.py} +7 -2
  176. rapidtide/scripts/{temporaldecomp → temporaldecomp.py} +7 -2
  177. rapidtide/scripts/{testhrv → testhrv.py} +1 -1
  178. rapidtide/scripts/{threeD → threeD.py} +7 -2
  179. rapidtide/scripts/{tidepool → tidepool.py} +7 -2
  180. rapidtide/scripts/{variabilityizer → variabilityizer.py} +7 -2
  181. rapidtide/simFuncClasses.py +2113 -0
  182. rapidtide/simfuncfit.py +312 -108
  183. rapidtide/stats.py +579 -247
  184. rapidtide/tests/.coveragerc +27 -6
  185. rapidtide-2.9.5.data/scripts/fdica → rapidtide/tests/cleanposttest +4 -6
  186. rapidtide/tests/happycomp +9 -0
  187. rapidtide/tests/resethappytargets +1 -1
  188. rapidtide/tests/resetrapidtidetargets +1 -1
  189. rapidtide/tests/resettargets +1 -1
  190. rapidtide/tests/runlocaltest +3 -3
  191. rapidtide/tests/showkernels +1 -1
  192. rapidtide/tests/test_aliasedcorrelate.py +4 -4
  193. rapidtide/tests/test_aligntcs.py +1 -1
  194. rapidtide/tests/test_calcicc.py +1 -1
  195. rapidtide/tests/test_cleanregressor.py +184 -0
  196. rapidtide/tests/test_congrid.py +70 -81
  197. rapidtide/tests/test_correlate.py +1 -1
  198. rapidtide/tests/test_corrpass.py +4 -4
  199. rapidtide/tests/test_delayestimation.py +54 -59
  200. rapidtide/tests/test_dlfiltertorch.py +437 -0
  201. rapidtide/tests/test_doresample.py +2 -2
  202. rapidtide/tests/test_externaltools.py +69 -0
  203. rapidtide/tests/test_fastresampler.py +9 -5
  204. rapidtide/tests/test_filter.py +96 -57
  205. rapidtide/tests/test_findmaxlag.py +50 -19
  206. rapidtide/tests/test_fullrunhappy_v1.py +15 -10
  207. rapidtide/tests/test_fullrunhappy_v2.py +19 -13
  208. rapidtide/tests/test_fullrunhappy_v3.py +28 -13
  209. rapidtide/tests/test_fullrunhappy_v4.py +30 -11
  210. rapidtide/tests/test_fullrunhappy_v5.py +62 -0
  211. rapidtide/tests/test_fullrunrapidtide_v1.py +61 -7
  212. rapidtide/tests/test_fullrunrapidtide_v2.py +27 -15
  213. rapidtide/tests/test_fullrunrapidtide_v3.py +28 -8
  214. rapidtide/tests/test_fullrunrapidtide_v4.py +16 -8
  215. rapidtide/tests/test_fullrunrapidtide_v5.py +15 -6
  216. rapidtide/tests/test_fullrunrapidtide_v6.py +142 -0
  217. rapidtide/tests/test_fullrunrapidtide_v7.py +114 -0
  218. rapidtide/tests/test_fullrunrapidtide_v8.py +66 -0
  219. rapidtide/tests/test_getparsers.py +158 -0
  220. rapidtide/tests/test_io.py +59 -18
  221. rapidtide/tests/{test_glmpass.py → test_linfitfiltpass.py} +10 -10
  222. rapidtide/tests/test_mi.py +1 -1
  223. rapidtide/tests/test_miscmath.py +1 -1
  224. rapidtide/tests/test_motionregress.py +5 -5
  225. rapidtide/tests/test_nullcorr.py +6 -9
  226. rapidtide/tests/test_padvec.py +216 -0
  227. rapidtide/tests/test_parserfuncs.py +101 -0
  228. rapidtide/tests/test_phaseanalysis.py +1 -1
  229. rapidtide/tests/test_rapidtideparser.py +59 -53
  230. rapidtide/tests/test_refinedelay.py +296 -0
  231. rapidtide/tests/test_runmisc.py +5 -5
  232. rapidtide/tests/test_sharedmem.py +60 -0
  233. rapidtide/tests/test_simroundtrip.py +132 -0
  234. rapidtide/tests/test_simulate.py +1 -1
  235. rapidtide/tests/test_stcorrelate.py +4 -2
  236. rapidtide/tests/test_timeshift.py +2 -2
  237. rapidtide/tests/test_valtoindex.py +1 -1
  238. rapidtide/tests/test_zRapidtideDataset.py +5 -3
  239. rapidtide/tests/utils.py +10 -9
  240. rapidtide/tidepoolTemplate.py +88 -70
  241. rapidtide/tidepoolTemplate.ui +60 -46
  242. rapidtide/tidepoolTemplate_alt.py +88 -53
  243. rapidtide/tidepoolTemplate_alt.ui +62 -52
  244. rapidtide/tidepoolTemplate_alt_qt6.py +921 -0
  245. rapidtide/tidepoolTemplate_big.py +1125 -0
  246. rapidtide/tidepoolTemplate_big.ui +2386 -0
  247. rapidtide/tidepoolTemplate_big_qt6.py +1129 -0
  248. rapidtide/tidepoolTemplate_qt6.py +793 -0
  249. rapidtide/util.py +1389 -148
  250. rapidtide/voxelData.py +1048 -0
  251. rapidtide/wiener.py +138 -25
  252. rapidtide/wiener2.py +114 -8
  253. rapidtide/workflows/adjustoffset.py +107 -5
  254. rapidtide/workflows/aligntcs.py +86 -3
  255. rapidtide/workflows/applydlfilter.py +231 -89
  256. rapidtide/workflows/applyppgproc.py +540 -0
  257. rapidtide/workflows/atlasaverage.py +309 -48
  258. rapidtide/workflows/atlastool.py +130 -9
  259. rapidtide/workflows/calcSimFuncMap.py +490 -0
  260. rapidtide/workflows/calctexticc.py +202 -10
  261. rapidtide/workflows/ccorrica.py +123 -15
  262. rapidtide/workflows/cleanregressor.py +415 -0
  263. rapidtide/workflows/delayvar.py +1268 -0
  264. rapidtide/workflows/diffrois.py +84 -6
  265. rapidtide/workflows/endtidalproc.py +149 -9
  266. rapidtide/workflows/fdica.py +197 -17
  267. rapidtide/workflows/filtnifti.py +71 -4
  268. rapidtide/workflows/filttc.py +76 -5
  269. rapidtide/workflows/fitSimFuncMap.py +578 -0
  270. rapidtide/workflows/fixtr.py +74 -4
  271. rapidtide/workflows/gmscalc.py +116 -6
  272. rapidtide/workflows/happy.py +1242 -480
  273. rapidtide/workflows/happy2std.py +145 -13
  274. rapidtide/workflows/happy_parser.py +277 -59
  275. rapidtide/workflows/histnifti.py +120 -4
  276. rapidtide/workflows/histtc.py +85 -4
  277. rapidtide/workflows/{glmfilt.py → linfitfilt.py} +128 -14
  278. rapidtide/workflows/localflow.py +329 -29
  279. rapidtide/workflows/mergequality.py +80 -4
  280. rapidtide/workflows/niftidecomp.py +323 -19
  281. rapidtide/workflows/niftistats.py +178 -8
  282. rapidtide/workflows/pairproc.py +99 -5
  283. rapidtide/workflows/pairwisemergenifti.py +86 -3
  284. rapidtide/workflows/parser_funcs.py +1488 -56
  285. rapidtide/workflows/physiofreq.py +139 -12
  286. rapidtide/workflows/pixelcomp.py +211 -9
  287. rapidtide/workflows/plethquality.py +105 -23
  288. rapidtide/workflows/polyfitim.py +159 -19
  289. rapidtide/workflows/proj2flow.py +76 -3
  290. rapidtide/workflows/rankimage.py +115 -8
  291. rapidtide/workflows/rapidtide.py +1833 -1919
  292. rapidtide/workflows/rapidtide2std.py +101 -3
  293. rapidtide/workflows/rapidtide_parser.py +607 -372
  294. rapidtide/workflows/refineDelayMap.py +249 -0
  295. rapidtide/workflows/refineRegressor.py +1215 -0
  296. rapidtide/workflows/regressfrommaps.py +308 -0
  297. rapidtide/workflows/resamplenifti.py +86 -4
  298. rapidtide/workflows/resampletc.py +92 -4
  299. rapidtide/workflows/retrolagtcs.py +442 -0
  300. rapidtide/workflows/retroregress.py +1501 -0
  301. rapidtide/workflows/roisummarize.py +176 -7
  302. rapidtide/workflows/runqualitycheck.py +72 -7
  303. rapidtide/workflows/showarbcorr.py +172 -16
  304. rapidtide/workflows/showhist.py +87 -3
  305. rapidtide/workflows/showstxcorr.py +161 -4
  306. rapidtide/workflows/showtc.py +172 -10
  307. rapidtide/workflows/showxcorrx.py +250 -62
  308. rapidtide/workflows/showxy.py +186 -16
  309. rapidtide/workflows/simdata.py +418 -112
  310. rapidtide/workflows/spatialfit.py +83 -8
  311. rapidtide/workflows/spatialmi.py +252 -29
  312. rapidtide/workflows/spectrogram.py +306 -33
  313. rapidtide/workflows/synthASL.py +157 -6
  314. rapidtide/workflows/tcfrom2col.py +77 -3
  315. rapidtide/workflows/tcfrom3col.py +75 -3
  316. rapidtide/workflows/tidepool.py +3829 -666
  317. rapidtide/workflows/utils.py +45 -19
  318. rapidtide/workflows/utils_doc.py +293 -0
  319. rapidtide/workflows/variabilityizer.py +118 -5
  320. {rapidtide-2.9.5.dist-info → rapidtide-3.1.3.dist-info}/METADATA +30 -223
  321. rapidtide-3.1.3.dist-info/RECORD +393 -0
  322. {rapidtide-2.9.5.dist-info → rapidtide-3.1.3.dist-info}/WHEEL +1 -1
  323. rapidtide-3.1.3.dist-info/entry_points.txt +65 -0
  324. rapidtide-3.1.3.dist-info/top_level.txt +2 -0
  325. rapidtide/calcandfitcorrpairs.py +0 -262
  326. rapidtide/data/examples/src/testoutputsize +0 -45
  327. rapidtide/data/models/model_revised/model.h5 +0 -0
  328. rapidtide/data/models/model_serdar/model.h5 +0 -0
  329. rapidtide/data/models/model_serdar2/model.h5 +0 -0
  330. rapidtide/data/reference/ASPECTS_nlin_asym_09c_2mm.nii.gz +0 -0
  331. rapidtide/data/reference/ASPECTS_nlin_asym_09c_2mm_mask.nii.gz +0 -0
  332. rapidtide/data/reference/ATTbasedFlowTerritories_split_nlin_asym_09c_2mm.nii.gz +0 -0
  333. rapidtide/data/reference/ATTbasedFlowTerritories_split_nlin_asym_09c_2mm_mask.nii.gz +0 -0
  334. rapidtide/data/reference/HCP1200_binmask_2mm_2009c_asym.nii.gz +0 -0
  335. rapidtide/data/reference/HCP1200_lag_2mm_2009c_asym.nii.gz +0 -0
  336. rapidtide/data/reference/HCP1200_mask_2mm_2009c_asym.nii.gz +0 -0
  337. rapidtide/data/reference/HCP1200_negmask_2mm_2009c_asym.nii.gz +0 -0
  338. rapidtide/data/reference/HCP1200_sigma_2mm_2009c_asym.nii.gz +0 -0
  339. rapidtide/data/reference/HCP1200_strength_2mm_2009c_asym.nii.gz +0 -0
  340. rapidtide/glmpass.py +0 -434
  341. rapidtide/refine_factored.py +0 -641
  342. rapidtide/scripts/retroglm +0 -23
  343. rapidtide/workflows/glmfrommaps.py +0 -202
  344. rapidtide/workflows/retroglm.py +0 -643
  345. rapidtide-2.9.5.data/scripts/adjustoffset +0 -23
  346. rapidtide-2.9.5.data/scripts/aligntcs +0 -23
  347. rapidtide-2.9.5.data/scripts/applydlfilter +0 -23
  348. rapidtide-2.9.5.data/scripts/atlasaverage +0 -23
  349. rapidtide-2.9.5.data/scripts/atlastool +0 -23
  350. rapidtide-2.9.5.data/scripts/calcicc +0 -22
  351. rapidtide-2.9.5.data/scripts/calctexticc +0 -23
  352. rapidtide-2.9.5.data/scripts/calcttest +0 -22
  353. rapidtide-2.9.5.data/scripts/ccorrica +0 -23
  354. rapidtide-2.9.5.data/scripts/diffrois +0 -23
  355. rapidtide-2.9.5.data/scripts/endtidalproc +0 -23
  356. rapidtide-2.9.5.data/scripts/filtnifti +0 -23
  357. rapidtide-2.9.5.data/scripts/filttc +0 -23
  358. rapidtide-2.9.5.data/scripts/fingerprint +0 -593
  359. rapidtide-2.9.5.data/scripts/fixtr +0 -23
  360. rapidtide-2.9.5.data/scripts/glmfilt +0 -24
  361. rapidtide-2.9.5.data/scripts/gmscalc +0 -22
  362. rapidtide-2.9.5.data/scripts/happy +0 -25
  363. rapidtide-2.9.5.data/scripts/happy2std +0 -23
  364. rapidtide-2.9.5.data/scripts/happywarp +0 -350
  365. rapidtide-2.9.5.data/scripts/histnifti +0 -23
  366. rapidtide-2.9.5.data/scripts/histtc +0 -23
  367. rapidtide-2.9.5.data/scripts/localflow +0 -23
  368. rapidtide-2.9.5.data/scripts/mergequality +0 -23
  369. rapidtide-2.9.5.data/scripts/pairproc +0 -23
  370. rapidtide-2.9.5.data/scripts/pairwisemergenifti +0 -23
  371. rapidtide-2.9.5.data/scripts/physiofreq +0 -23
  372. rapidtide-2.9.5.data/scripts/pixelcomp +0 -23
  373. rapidtide-2.9.5.data/scripts/plethquality +0 -23
  374. rapidtide-2.9.5.data/scripts/polyfitim +0 -23
  375. rapidtide-2.9.5.data/scripts/proj2flow +0 -23
  376. rapidtide-2.9.5.data/scripts/rankimage +0 -23
  377. rapidtide-2.9.5.data/scripts/rapidtide +0 -23
  378. rapidtide-2.9.5.data/scripts/rapidtide2std +0 -23
  379. rapidtide-2.9.5.data/scripts/resamplenifti +0 -23
  380. rapidtide-2.9.5.data/scripts/resampletc +0 -23
  381. rapidtide-2.9.5.data/scripts/retroglm +0 -23
  382. rapidtide-2.9.5.data/scripts/roisummarize +0 -23
  383. rapidtide-2.9.5.data/scripts/runqualitycheck +0 -23
  384. rapidtide-2.9.5.data/scripts/showarbcorr +0 -23
  385. rapidtide-2.9.5.data/scripts/showhist +0 -23
  386. rapidtide-2.9.5.data/scripts/showstxcorr +0 -23
  387. rapidtide-2.9.5.data/scripts/showtc +0 -23
  388. rapidtide-2.9.5.data/scripts/showxcorr_legacy +0 -536
  389. rapidtide-2.9.5.data/scripts/showxcorrx +0 -23
  390. rapidtide-2.9.5.data/scripts/showxy +0 -23
  391. rapidtide-2.9.5.data/scripts/simdata +0 -23
  392. rapidtide-2.9.5.data/scripts/spatialdecomp +0 -23
  393. rapidtide-2.9.5.data/scripts/spatialfit +0 -23
  394. rapidtide-2.9.5.data/scripts/spatialmi +0 -23
  395. rapidtide-2.9.5.data/scripts/spectrogram +0 -23
  396. rapidtide-2.9.5.data/scripts/synthASL +0 -23
  397. rapidtide-2.9.5.data/scripts/tcfrom2col +0 -23
  398. rapidtide-2.9.5.data/scripts/tcfrom3col +0 -23
  399. rapidtide-2.9.5.data/scripts/temporaldecomp +0 -23
  400. rapidtide-2.9.5.data/scripts/threeD +0 -236
  401. rapidtide-2.9.5.data/scripts/tidepool +0 -23
  402. rapidtide-2.9.5.data/scripts/variabilityizer +0 -23
  403. rapidtide-2.9.5.dist-info/RECORD +0 -357
  404. rapidtide-2.9.5.dist-info/top_level.txt +0 -86
  405. {rapidtide-2.9.5.dist-info → rapidtide-3.1.3.dist-info/licenses}/LICENSE +0 -0
rapidtide/dlfilter.py CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env python
2
2
  # -*- coding: utf-8 -*-
3
3
  #
4
- # Copyright 2016-2024 Blaise Frederick
4
+ # Copyright 2016-2025 Blaise Frederick
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -16,11 +16,6 @@
16
16
  # limitations under the License.
17
17
  #
18
18
  #
19
- """
20
- Created on Sat Jul 28 23:01:07 2018
21
-
22
- @author: neuro
23
- """
24
19
  import glob
25
20
  import logging
26
21
  import os
@@ -31,6 +26,7 @@ import warnings
31
26
  import matplotlib as mpl
32
27
  import matplotlib.pyplot as plt
33
28
  import numpy as np
29
+ from numpy.typing import NDArray
34
30
 
35
31
  with warnings.catch_warnings():
36
32
  warnings.simplefilter("ignore")
@@ -41,7 +37,6 @@ with warnings.catch_warnings():
41
37
  else:
42
38
  pyfftwpresent = True
43
39
 
44
-
45
40
  from scipy import fftpack
46
41
  from statsmodels.robust.scale import mad
47
42
 
@@ -49,102 +44,52 @@ if pyfftwpresent:
49
44
  fftpack = pyfftw.interfaces.scipy_fftpack
50
45
  pyfftw.interfaces.cache.enable()
51
46
 
47
+ import tensorflow as tf
48
+ import tf_keras.backend as K
49
+ from tf_keras.callbacks import (
50
+ EarlyStopping,
51
+ ModelCheckpoint,
52
+ TensorBoard,
53
+ TerminateOnNaN,
54
+ )
55
+ from tf_keras.layers import (
56
+ LSTM,
57
+ Activation,
58
+ BatchNormalization,
59
+ Bidirectional,
60
+ Concatenate,
61
+ Convolution1D,
62
+ Dense,
63
+ Dropout,
64
+ Flatten,
65
+ GlobalMaxPool1D,
66
+ Input,
67
+ MaxPooling1D,
68
+ Reshape,
69
+ TimeDistributed,
70
+ UpSampling1D,
71
+ )
72
+ from tf_keras.models import Model, Sequential, load_model
73
+ from tf_keras.optimizers.legacy import RMSprop
74
+
52
75
  import rapidtide.io as tide_io
53
76
 
77
+ os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
78
+
54
79
  LGR = logging.getLogger("GENERAL")
55
80
  LGR.debug("setting backend to Agg")
56
81
  mpl.use("Agg")
57
82
 
58
- tfversion = -1
59
- try:
60
- import plaidml.keras
61
-
62
- plaidml.keras.install_backend("plaidml")
63
- tfversion = 0
64
- LGR.debug("using plaidml keras")
65
- from keras.callbacks import ModelCheckpoint, TerminateOnNaN
66
- from keras.layers import (
67
- LSTM,
68
- Activation,
69
- BatchNormalization,
70
- Bidirectional,
71
- Concatenate,
72
- Conv1D,
73
- Dense,
74
- Dropout,
75
- GlobalMaxPool1D,
76
- Input,
77
- MaxPooling1D,
78
- TimeDistributed,
79
- UpSampling1D,
80
- )
81
- from keras.models import Model, Sequential, load_model
82
- from keras.optimizers import RMSprop
83
- except ImportError:
84
- tfversion = -1
85
- LGR.warning("import plaidml.keras failed: falling back to standard tensorflow keras")
86
-
87
- if tfversion == -1:
88
- try:
89
- import tensorflow.compat.v1 as tf
90
-
91
- if tf.__version__[0] == "2":
92
- tfversion = 2
93
- elif tf.__version__[0] == "1":
94
- tfversion = 1
95
- else:
96
- LGR.warning(f"could not interpret {tf.__version__[0]}")
97
- LGR.debug(f"tensorflow version is {tfversion}")
98
- except ImportError:
99
- raise ImportError("no backend found - exiting")
100
-
101
- if tfversion == 2:
102
- LGR.debug("using tensorflow v2x")
103
- tf.disable_v2_behavior()
104
- from tensorflow.keras.callbacks import ModelCheckpoint, TerminateOnNaN
105
- from tensorflow.keras.layers import (
106
- LSTM,
107
- Activation,
108
- BatchNormalization,
109
- Bidirectional,
110
- Convolution1D,
111
- Dense,
112
- Dropout,
113
- GlobalMaxPool1D,
114
- MaxPooling1D,
115
- TimeDistributed,
116
- UpSampling1D,
117
- )
118
- from tensorflow.keras.models import Sequential, load_model
119
- from tensorflow.keras.optimizers import RMSprop
120
-
121
- LGR.debug(f"tensorflow version: >>>{tf.__version__}<<<")
122
- elif tfversion == 1:
123
- LGR.debug("using tensorflow v1x")
124
- from keras.callbacks import ModelCheckpoint, TerminateOnNaN
125
- from keras.layers import (
126
- LSTM,
127
- Activation,
128
- BatchNormalization,
129
- Bidirectional,
130
- Concatenate,
131
- Conv1D,
132
- Dense,
133
- Dropout,
134
- GlobalMaxPool1D,
135
- Input,
136
- MaxPooling1D,
137
- TimeDistributed,
138
- UpSampling1D,
139
- )
140
- from keras.models import Model, Sequential, load_model, model_from_json
141
- from keras.optimizers import RMSprop
83
+ # Disable GPU if desired
84
+ # figure out what sorts of devices we have
85
+ physical_devices = tf.config.list_physical_devices()
86
+ print(physical_devices)
87
+ # try:
88
+ # tf.config.set_visible_devices([], "GPU")
89
+ # except Exception as e:
90
+ # LGR.warning(f"Failed to disable GPU: {e}")
142
91
 
143
- LGR.debug(f"tensorflow version: >>>{tf.__version__}<<<")
144
- elif tfversion == 0:
145
- pass
146
- else:
147
- raise ImportError("could not find backend - exiting")
92
+ LGR.debug(f"tensorflow version: >>>{tf.__version__}<<<")
148
93
 
149
94
 
150
95
  class DeepLearningFilter:
@@ -172,37 +117,190 @@ class DeepLearningFilter:
172
117
  model = None
173
118
  modelpath = None
174
119
  inputsize = None
175
- usehdf = True
176
120
  infodict = {}
177
121
 
178
122
  def __init__(
179
123
  self,
180
- window_size=128,
181
- num_layers=5,
182
- dropout_rate=0.3,
183
- num_pretrain_epochs=0,
184
- num_epochs=1,
185
- activation="relu",
186
- modelroot=".",
187
- dofft=False,
188
- excludethresh=4.0,
189
- usebadpts=False,
190
- thesuffix="25.0Hz",
191
- modelpath=".",
192
- usehdf=True,
193
- thedatadir="/Users/frederic/Documents/MR_data/physioconn/timecourses",
194
- inputfrag="abc",
195
- targetfrag="xyz",
196
- excludebysubject=True,
197
- startskip=200,
198
- endskip=200,
199
- step=1,
200
- namesuffix=None,
201
- readlim=None,
202
- readskip=None,
203
- countlim=None,
124
+ window_size: int = 128,
125
+ num_layers: int = 5,
126
+ dropout_rate: float = 0.3,
127
+ num_pretrain_epochs: int = 0,
128
+ num_epochs: int = 1,
129
+ activation: str = "relu",
130
+ modelroot: str = ".",
131
+ dofft: bool = False,
132
+ excludethresh: float = 4.0,
133
+ usebadpts: bool = False,
134
+ thesuffix: str = "25.0Hz",
135
+ modelpath: str = ".",
136
+ thedatadir: str = "/Users/frederic/Documents/MR_data/physioconn/timecourses",
137
+ inputfrag: str = "abc",
138
+ targetfrag: str = "xyz",
139
+ corrthresh_rp: float = 0.5,
140
+ excludebysubject: bool = True,
141
+ startskip: int = 200,
142
+ endskip: int = 200,
143
+ step: int = 1,
144
+ namesuffix: str | None = None,
145
+ readlim: int | None = None,
146
+ readskip: int | None = None,
147
+ countlim: int | None = None,
204
148
  **kwargs,
205
- ):
149
+ ) -> None:
150
+ """
151
+ Initialize the DeepLearningFilter with specified parameters.
152
+
153
+ This constructor sets up the configuration for a deep learning model used
154
+ for filtering physiological timecourses. It initializes various hyperparameters,
155
+ paths, and flags that control the behavior of the model and data processing.
156
+
157
+ Parameters
158
+ ----------
159
+ window_size : int, optional
160
+ Size of the sliding window used for processing time series data. Default is 128.
161
+ num_layers : int, optional
162
+ Number of layers in the neural network model. Default is 5.
163
+ dropout_rate : float, optional
164
+ Dropout rate for regularization during training. Default is 0.3.
165
+ num_pretrain_epochs : int, optional
166
+ Number of pre-training epochs. Default is 0.
167
+ num_epochs : int, optional
168
+ Number of training epochs. Default is 1.
169
+ activation : str, optional
170
+ Activation function to use in the model. Default is "relu".
171
+ modelroot : str, optional
172
+ Root directory for model storage. Default is ".".
173
+ dofft : bool, optional
174
+ Whether to apply FFT transformation to input data. Default is False.
175
+ excludethresh : float, optional
176
+ Threshold for excluding data points based on correlation. Default is 4.0.
177
+ usebadpts : bool, optional
178
+ Whether to include bad points in the input. Default is False.
179
+ thesuffix : str, optional
180
+ Suffix to append to filenames. Default is "25.0Hz".
181
+ modelpath : str, optional
182
+ Path to save or load the model. Default is ".".
183
+ thedatadir : str, optional
184
+ Directory containing the physiological data files. Default is
185
+ "/Users/frederic/Documents/MR_data/physioconn/timecourses".
186
+ inputfrag : str, optional
187
+ Fragment identifier for input data. Default is "abc".
188
+ targetfrag : str, optional
189
+ Fragment identifier for target data. Default is "xyz".
190
+ corrthresh_rp : float, optional
191
+ Correlation threshold for filtering. Default is 0.5.
192
+ excludebysubject : bool, optional
193
+ Whether to exclude data by subject. Default is True.
194
+ startskip : int, optional
195
+ Number of samples to skip at the beginning of each timecourse. Default is 200.
196
+ endskip : int, optional
197
+ Number of samples to skip at the end of each timecourse. Default is 200.
198
+ step : int, optional
199
+ Step size for sliding window. Default is 1.
200
+ namesuffix : str, optional
201
+ Suffix to append to model name. Default is None.
202
+ readlim : int, optional
203
+ Limit on number of samples to read. Default is None.
204
+ readskip : int, optional
205
+ Number of samples to skip when reading data. Default is None.
206
+ countlim : int, optional
207
+ Limit on number of timecourses to process. Default is None.
208
+ **kwargs
209
+ Additional keyword arguments passed to the parent class.
210
+
211
+ Notes
212
+ -----
213
+ The `inputsize` is dynamically set based on the `usebadpts` flag:
214
+ - If `usebadpts` is True, input size is 2.
215
+ - Otherwise, input size is 1.
216
+
217
+ Examples
218
+ --------
219
+ >>> filter = DeepLearningFilter(
220
+ ... window_size=256,
221
+ ... num_layers=6,
222
+ ... dropout_rate=0.2,
223
+ ... modelroot="/models",
224
+ ... dofft=True
225
+ ... )
226
+ """
227
+ """
228
+ Initialize the DeepLearningFilter with specified parameters.
229
+
230
+ This constructor sets up the configuration for a deep learning model used
231
+ for filtering physiological timecourses. It initializes various hyperparameters,
232
+ paths, and flags that control the behavior of the model and data processing.
233
+
234
+ Parameters
235
+ ----------
236
+ window_size : int, optional
237
+ Size of the sliding window used for processing time series data. Default is 128.
238
+ num_layers : int, optional
239
+ Number of layers in the neural network model. Default is 5.
240
+ dropout_rate : float, optional
241
+ Dropout rate for regularization during training. Default is 0.3.
242
+ num_pretrain_epochs : int, optional
243
+ Number of pre-training epochs. Default is 0.
244
+ num_epochs : int, optional
245
+ Number of training epochs. Default is 1.
246
+ activation : str, optional
247
+ Activation function to use in the model. Default is "relu".
248
+ modelroot : str, optional
249
+ Root directory for model storage. Default is ".".
250
+ dofft : bool, optional
251
+ Whether to apply FFT transformation to input data. Default is False.
252
+ excludethresh : float, optional
253
+ Threshold for excluding data points based on correlation. Default is 4.0.
254
+ usebadpts : bool, optional
255
+ Whether to include bad points in the input. Default is False.
256
+ thesuffix : str, optional
257
+ Suffix to append to filenames. Default is "25.0Hz".
258
+ modelpath : str, optional
259
+ Path to save or load the model. Default is ".".
260
+ thedatadir : str, optional
261
+ Directory containing the physiological data files. Default is
262
+ "/Users/frederic/Documents/MR_data/physioconn/timecourses".
263
+ inputfrag : str, optional
264
+ Fragment identifier for input data. Default is "abc".
265
+ targetfrag : str, optional
266
+ Fragment identifier for target data. Default is "xyz".
267
+ corrthresh_rp : float, optional
268
+ Correlation threshold for filtering. Default is 0.5.
269
+ excludebysubject : bool, optional
270
+ Whether to exclude data by subject. Default is True.
271
+ startskip : int, optional
272
+ Number of samples to skip at the beginning of each timecourse. Default is 200.
273
+ endskip : int, optional
274
+ Number of samples to skip at the end of each timecourse. Default is 200.
275
+ step : int, optional
276
+ Step size for sliding window. Default is 1.
277
+ namesuffix : str, optional
278
+ Suffix to append to model name. Default is None.
279
+ readlim : int, optional
280
+ Limit on number of samples to read. Default is None.
281
+ readskip : int, optional
282
+ Number of samples to skip when reading data. Default is None.
283
+ countlim : int, optional
284
+ Limit on number of timecourses to process. Default is None.
285
+ **kwargs
286
+ Additional keyword arguments passed to the parent class.
287
+
288
+ Notes
289
+ -----
290
+ The `inputsize` is dynamically set based on the `usebadpts` flag:
291
+ - If `usebadpts` is True, input size is 2.
292
+ - Otherwise, input size is 1.
293
+
294
+ Examples
295
+ --------
296
+ >>> filter = DeepLearningFilter(
297
+ ... window_size=256,
298
+ ... num_layers=6,
299
+ ... dropout_rate=0.2,
300
+ ... modelroot="/models",
301
+ ... dofft=True
302
+ ... )
303
+ """
206
304
  self.window_size = window_size
207
305
  self.dropout_rate = dropout_rate
208
306
  self.num_pretrain_epochs = num_pretrain_epochs
@@ -215,12 +313,12 @@ class DeepLearningFilter:
215
313
  self.inputsize = 1
216
314
  self.activation = activation
217
315
  self.modelroot = modelroot
218
- self.usehdf = usehdf
219
316
  self.dofft = dofft
220
317
  self.thesuffix = thesuffix
221
318
  self.thedatadir = thedatadir
222
319
  self.modelpath = modelpath
223
320
  LGR.info(f"modeldir from DeepLearningFilter: {self.modelpath}")
321
+ self.corrthresh_rp = corrthresh_rp
224
322
  self.excludethresh = excludethresh
225
323
  self.readlim = readlim
226
324
  self.readskip = readskip
@@ -241,6 +339,7 @@ class DeepLearningFilter:
241
339
  self.infodict["window_size"] = self.window_size
242
340
  self.infodict["usebadpts"] = self.usebadpts
243
341
  self.infodict["dofft"] = self.dofft
342
+ self.infodict["corrthresh_rp"] = self.corrthresh_rp
244
343
  self.infodict["excludethresh"] = self.excludethresh
245
344
  self.infodict["num_pretrain_epochs"] = self.num_pretrain_epochs
246
345
  self.infodict["num_epochs"] = self.num_epochs
@@ -251,7 +350,91 @@ class DeepLearningFilter:
251
350
  self.infodict["step"] = self.step
252
351
  self.infodict["train_arch"] = sys.platform
253
352
 
254
- def loaddata(self):
353
+ def loaddata(self) -> None:
354
+ """
355
+ Load and preprocess data for training and validation.
356
+
357
+ This method initializes the data loading process by calling the `prep` function
358
+ with a set of parameters derived from the instance attributes. It handles both
359
+ FFT and non-FFT modes of data preprocessing. The loaded data is stored in
360
+ instance variables for use in subsequent training steps.
361
+
362
+ Parameters
363
+ ----------
364
+ self : object
365
+ The instance of the class containing the following attributes:
366
+ - initialized : bool
367
+ Indicates whether the model has been initialized.
368
+ - dofft : bool
369
+ Whether to apply FFT transformation to the data.
370
+ - window_size : int
371
+ Size of the sliding window used for data segmentation.
372
+ - thesuffix : str
373
+ Suffix to append to filenames when reading data.
374
+ - thedatadir : str
375
+ Directory path where the data files are located.
376
+ - inputfrag : str
377
+ Fragment identifier for input data.
378
+ - targetfrag : str
379
+ Fragment identifier for target data.
380
+ - startskip : int
381
+ Number of samples to skip at the beginning of each file.
382
+ - endskip : int
383
+ Number of samples to skip at the end of each file.
384
+ - corrthresh_rp : float
385
+ Correlation threshold for filtering data.
386
+ - step : int
387
+ Step size for sliding window.
388
+ - usebadpts : bool
389
+ Whether to include bad points in the data.
390
+ - excludethresh : float
391
+ Threshold for excluding data points.
392
+ - excludebysubject : bool
393
+ Whether to exclude data by subject.
394
+ - readlim : int
395
+ Limit on the number of samples to read.
396
+ - readskip : int
397
+ Number of samples to skip while reading.
398
+ - countlim : int
399
+ Limit on the number of data points to process.
400
+
401
+ Returns
402
+ -------
403
+ None
404
+ This method does not return any value. It modifies the instance attributes
405
+ in place.
406
+
407
+ Raises
408
+ ------
409
+ Exception
410
+ If the model is not initialized prior to calling this method.
411
+
412
+ Notes
413
+ -----
414
+ The method assigns the following attributes to the instance after loading:
415
+ - train_x : array-like
416
+ Training input data.
417
+ - train_y : array-like
418
+ Training target data.
419
+ - val_x : array-like
420
+ Validation input data.
421
+ - val_y : array-like
422
+ Validation target data.
423
+ - Ns : int
424
+ Number of samples.
425
+ - tclen : int
426
+ Length of time series.
427
+ - thebatchsize : int
428
+ Batch size for training.
429
+
430
+ Examples
431
+ --------
432
+ >>> model = MyModel()
433
+ >>> model.initialized = True
434
+ >>> model.loaddata()
435
+ >>> print(model.train_x.shape)
436
+ (1000, 10)
437
+ """
255
438
  if not self.initialized:
256
439
  raise Exception("model must be initialized prior to loading data")
257
440
 
@@ -274,6 +457,7 @@ class DeepLearningFilter:
274
457
  targetfrag=self.targetfrag,
275
458
  startskip=self.startskip,
276
459
  endskip=self.endskip,
460
+ corrthresh_rp=self.corrthresh_rp,
277
461
  step=self.step,
278
462
  dofft=self.dofft,
279
463
  usebadpts=self.usebadpts,
@@ -300,6 +484,7 @@ class DeepLearningFilter:
300
484
  targetfrag=self.targetfrag,
301
485
  startskip=self.startskip,
302
486
  endskip=self.endskip,
487
+ corrthresh_rp=self.corrthresh_rp,
303
488
  step=self.step,
304
489
  dofft=self.dofft,
305
490
  usebadpts=self.usebadpts,
@@ -310,11 +495,92 @@ class DeepLearningFilter:
310
495
  countlim=self.countlim,
311
496
  )
312
497
 
313
- def evaluate(self):
498
+ @tf.function
499
+ def predict_model(self, X: NDArray) -> NDArray:
500
+ """
501
+ Make predictions using the trained model.
502
+
503
+ Parameters
504
+ ----------
505
+ X : NDArray
506
+ Input features for prediction. Shape should be (n_samples, n_features)
507
+ where n_samples is the number of samples and n_features is the number
508
+ of features expected by the model.
509
+
510
+ Returns
511
+ -------
512
+ NDArray
513
+ Model predictions. Shape will depend on the specific model type but
514
+ typically follows (n_samples,) for regression or (n_samples, n_classes)
515
+ for classification.
516
+
517
+ Notes
518
+ -----
519
+ This method sets the model to inference mode by calling with training=False.
520
+ The predictions are made without computing gradients, making it efficient
521
+ for inference tasks.
522
+
523
+ Examples
524
+ --------
525
+ >>> # Assuming model is already trained
526
+ >>> X_test = np.array([[1.0, 2.0], [3.0, 4.0]])
527
+ >>> predictions = model.predict_model(X_test)
528
+ >>> print(predictions)
529
+ """
530
+ return self.model(X, training=False)
531
+
532
+ def evaluate(self) -> tuple[list, list, float, float]:
533
+ """
534
+ Evaluate the model performance on validation data and compute loss metrics.
535
+
536
+ This method performs model evaluation by computing prediction errors and
537
+ saving training/validation loss curves. It calculates both prediction error
538
+ (difference between predicted and actual values) and raw error (difference
539
+ between input and actual values). The method also generates and saves a
540
+ plot of the training and validation loss over epochs.
541
+
542
+ Parameters
543
+ ----------
544
+ self : object
545
+ The instance of the class containing the model and data attributes.
546
+
547
+ Returns
548
+ -------
549
+ tuple[list, list, float, float]
550
+ A tuple containing:
551
+ - training_loss : list
552
+ List of training loss values per epoch
553
+ - validation_loss : list
554
+ List of validation loss values per epoch
555
+ - prediction_error : float
556
+ Mean squared error between predicted and actual values
557
+ - raw_error : float
558
+ Mean squared error between input features and actual values
559
+
560
+ Notes
561
+ -----
562
+ This method modifies the instance attributes:
563
+ - self.lossfilename: Path to the saved loss plot
564
+ - self.pred_error: Computed prediction error
565
+ - self.raw_error: Computed raw error
566
+ - self.loss: Training loss history
567
+ - self.val_loss: Validation loss history
568
+
569
+ The method saves:
570
+ - Loss plot as PNG file
571
+ - Loss metrics as text file
572
+
573
+ Examples
574
+ --------
575
+ >>> model = MyModel()
576
+ >>> train_loss, val_loss, pred_error, raw_error = model.evaluate()
577
+ >>> print(f"Prediction Error: {pred_error}")
578
+ Prediction Error: 0.1234
579
+ """
314
580
  self.lossfilename = os.path.join(self.modelname, "loss.png")
315
581
  LGR.info(f"lossfilename: {self.lossfilename}")
316
582
 
317
- YPred = self.model.predict(self.val_x)
583
+ YPred = self.predict_model(self.val_x).numpy()
318
584
 
319
585
  error = self.val_y - YPred
320
586
  self.pred_error = np.mean(np.square(error))
@@ -351,7 +617,44 @@ class DeepLearningFilter:
351
617
 
352
618
  return self.loss, self.val_loss, self.pred_error, self.raw_error
353
619
 
354
- def initmetadata(self):
620
+ def initmetadata(self) -> None:
621
+ """
622
+ Initialize and store metadata information for the model.
623
+
624
+ This function creates a dictionary containing various model configuration parameters
625
+ and writes them to a JSON file for future reference and reproducibility.
626
+
627
+ Parameters
628
+ ----------
629
+ self : object
630
+ The instance of the class containing the metadata attributes.
631
+
632
+ Returns
633
+ -------
634
+ None
635
+ This function does not return any value but writes metadata to a JSON file.
636
+
637
+ Notes
638
+ -----
639
+ The metadata includes:
640
+ - Window size for processing
641
+ - Bad point handling flag
642
+ - FFT usage flag
643
+ - Exclusion threshold
644
+ - Number of epochs and layers
645
+ - Dropout rate
646
+ - Operating system platform
647
+ - Model name
648
+
649
+ The metadata is saved to ``{modelname}/model_meta.json`` where ``modelname``
650
+ is the model's name attribute.
651
+
652
+ Examples
653
+ --------
654
+ >>> model = MyModel()
655
+ >>> model.initmetadata()
656
+ >>> # Metadata stored in modelname/model_meta.json
657
+ """
355
658
  self.infodict = {}
356
659
  self.infodict["window_size"] = self.window_size
357
660
  self.infodict["usebadpts"] = self.usebadpts
@@ -364,37 +667,153 @@ class DeepLearningFilter:
364
667
  self.infodict["modelname"] = self.modelname
365
668
  tide_io.writedicttojson(self.infodict, os.path.join(self.modelname, "model_meta.json"))
366
669
 
367
- def updatemetadata(self):
670
+ def updatemetadata(self) -> None:
671
+ """
672
+ Update metadata dictionary with model metrics and save to JSON file.
673
+
674
+ This method updates the internal information dictionary with various model
675
+ performance metrics and writes the complete metadata to a JSON file for
676
+ model persistence and tracking.
677
+
678
+ Parameters
679
+ ----------
680
+ self : object
681
+ The instance of the class containing the metadata and model information.
682
+ Expected to have the following attributes:
683
+ - infodict : dict
684
+ Dictionary containing model metadata.
685
+ - loss : float
686
+ Training loss value.
687
+ - val_loss : float
688
+ Validation loss value.
689
+ - raw_error : float
690
+ Raw error metric.
691
+ - pred_error : float
692
+ Prediction error metric.
693
+ - modelname : str
694
+ Name/path of the model for file output.
695
+
696
+ Returns
697
+ -------
698
+ None
699
+ This method does not return any value but modifies the `infodict` in-place
700
+ and writes to a JSON file.
701
+
702
+ Notes
703
+ -----
704
+ The method writes metadata to ``{modelname}/model_meta.json`` where
705
+ ``modelname`` is the model name attribute of the instance.
706
+
707
+ Examples
708
+ --------
709
+ >>> model = MyModel()
710
+ >>> model.updatemetadata()
711
+ >>> # Creates model_meta.json with loss, val_loss, raw_error, and pred_error
712
+ """
368
713
  self.infodict["loss"] = self.loss
369
714
  self.infodict["val_loss"] = self.val_loss
370
715
  self.infodict["raw_error"] = self.raw_error
371
716
  self.infodict["prediction_error"] = self.pred_error
372
717
  tide_io.writedicttojson(self.infodict, os.path.join(self.modelname, "model_meta.json"))
373
718
 
374
- def savemodel(self, usehdf=True):
375
- if usehdf:
376
- # save the trained model as a single hdf file
377
- self.model.save(os.path.join(self.modelname, "model.h5"))
719
+ def savemodel(self, altname: str | None = None) -> None:
720
+ """
721
+ Save the model to disk with the specified name.
722
+
723
+ This method saves the current model to a Keras file format (.keras) in a
724
+ directory named according to the model name or an alternative name provided.
725
+
726
+ Parameters
727
+ ----------
728
+ altname : str, optional
729
+ Alternative name to use for saving the model. If None, uses the
730
+ model's default name stored in `self.modelname`. Default is None.
731
+
732
+ Returns
733
+ -------
734
+ None
735
+ This method does not return any value.
736
+
737
+ Notes
738
+ -----
739
+ The model is saved in the Keras format (.keras) and stored in a directory
740
+ with the same name as the model. The method logs the saving operation
741
+ using the logger instance `LGR`.
742
+
743
+ Examples
744
+ --------
745
+ >>> # Save model with default name
746
+ >>> savemodel()
747
+ >>>
748
+ >>> # Save model with alternative name
749
+ >>> savemodel(altname="my_custom_model")
750
+ """
751
+ if altname is None:
752
+ modelsavename = self.modelname
378
753
  else:
379
- # save the model structure to JSON
380
- model_json = self.model.to_json()
381
- with open(os.path.join(self.modelname, "model.json"), "w") as json_file:
382
- json_file.write(model_json)
383
- # save the weights to hdf
384
- self.model.save_weights(os.path.join(self.modelname, "model_weights.h5"))
385
-
386
- def loadmodel(self, modelname, usehdf=True, verbose=False):
754
+ modelsavename = altname
755
+ LGR.info(f"saving {modelsavename}")
756
+ self.model.save(os.path.join(modelsavename, "model.keras"))
757
+
758
+ def loadmodel(self, modelname: str, verbose: bool = False) -> None:
759
+ """
760
+ Load a trained model from disk and initialize model parameters.
761
+
762
+ Load a Keras model from the specified model directory, along with associated
763
+ metadata and configuration information. The function attempts to load the model
764
+ in Keras format first, falling back to HDF5 format if the Keras format is not found.
765
+
766
+ Parameters
767
+ ----------
768
+ modelname : str
769
+ Name of the model to load, corresponding to a subdirectory in ``self.modelpath``.
770
+ verbose : bool, optional
771
+ If True, print model summary and metadata information. Default is False.
772
+
773
+ Returns
774
+ -------
775
+ None
776
+ This method modifies the instance attributes in-place and does not return anything.
777
+
778
+ Notes
779
+ -----
780
+ The function attempts to load the model in the following order:
781
+ 1. Keras format (``model.keras``)
782
+ 2. HDF5 format (``model.h5``)
783
+
784
+ If neither format is found, the function exits with an error message.
785
+
786
+ The loaded model metadata is stored in ``self.infodict``, and model configuration
787
+ is stored in ``self.config``. Additional attributes like ``window_size`` and ``usebadpts``
788
+ are extracted from the metadata and stored as instance attributes.
789
+
790
+ Examples
791
+ --------
792
+ >>> loader = ModelLoader()
793
+ >>> loader.loadmodel("my_model", verbose=True)
794
+ loading my_model
795
+ Model: "sequential"
796
+ _________________________________________________________________
797
+ Layer (type) Output Shape Param #
798
+ =================================================================
799
+ ...
800
+ >>> print(loader.window_size)
801
+ 100
802
+ """
387
803
  # read in the data
388
804
  LGR.info(f"loading {modelname}")
389
-
390
- if usehdf:
805
+ try:
806
+ # load the keras format model if it exists
807
+ self.model = load_model(os.path.join(self.modelpath, modelname, "model.keras"))
808
+ self.config = self.model.get_config()
809
+ except OSError:
391
810
  # load in the model with weights from hdf
392
- self.model = load_model(os.path.join(self.modelpath, modelname, "model.h5"))
393
- else:
394
- with open(os.path.join(self.modelname, "model.json"), "r") as json_file:
395
- loaded_model_json = json_file.read()
396
- self.model = model_from_json(loaded_model_json)
397
- self.model.load_weights(os.path.join(self.modelname, "model_weights.h5"))
811
+ try:
812
+ self.model = load_model(os.path.join(self.modelpath, modelname, "model.h5"))
813
+ except OSError:
814
+ print(f"Could not load {modelname}")
815
+ sys.exit()
816
+
398
817
  if verbose:
399
818
  self.model.summary()
400
819
 
@@ -402,74 +821,195 @@ class DeepLearningFilter:
402
821
  self.infodict = tide_io.readdictfromjson(
403
822
  os.path.join(self.modelpath, modelname, "model_meta.json")
404
823
  )
824
+ if verbose:
825
+ print(self.infodict)
405
826
  self.window_size = self.infodict["window_size"]
406
827
  self.usebadpts = self.infodict["usebadpts"]
407
828
 
408
829
  # model is ready to use
409
830
  self.initialized = True
410
831
  self.trained = True
411
-
412
- def initialize(self):
832
+ LGR.info(f"{modelname} loaded")
833
+
834
+ def initialize(self) -> None:
835
+ """
836
+ Initialize the model by setting up network architecture and metadata.
837
+
838
+ This method performs a series of initialization steps including retrieving
839
+ the model name, creating the network architecture, displaying model summary,
840
+ saving the model configuration, initializing metadata, and setting appropriate
841
+ flags to indicate initialization status.
842
+
843
+ Parameters
844
+ ----------
845
+ self : object
846
+ The instance of the model class being initialized.
847
+
848
+ Returns
849
+ -------
850
+ None
851
+ This method does not return any value.
852
+
853
+ Notes
854
+ -----
855
+ This method should be called before any training or prediction operations.
856
+ The initialization process sets `self.initialized` to True and `self.trained`
857
+ to False, indicating that the model is ready for training but has not been
858
+ trained yet.
859
+
860
+ Examples
861
+ --------
862
+ >>> model = MyModel()
863
+ >>> model.initialize()
864
+ >>> print(model.initialized)
865
+ True
866
+ >>> print(model.trained)
867
+ False
868
+ """
413
869
  self.getname()
414
870
  self.makenet()
415
871
  self.model.summary()
416
- self.savemodel(usehdf=True)
417
- self.savemodel(usehdf=False)
872
+ self.savemodel()
418
873
  self.initmetadata()
419
874
  self.initialized = True
420
875
  self.trained = False
421
876
 
422
- def train(self):
877
+ def train(self) -> None:
878
+ """
879
+ Train the model using the provided training and validation datasets.
880
+
881
+ This method performs model training with optional pretraining and logging. It supports
882
+ TensorBoard logging, model checkpointing, early stopping, and NaN termination. The trained
883
+ model is saved at the end of training.
884
+
885
+ Parameters
886
+ ----------
887
+ self : object
888
+ The instance of the class containing the model and training configuration.
889
+ Expected attributes include:
890
+ - `model`: The Keras model to be trained.
891
+ - `train_x`, `train_y`: Training data inputs and labels.
892
+ - `val_x`, `val_y`: Validation data inputs and labels.
893
+ - `modelname`: Name of the model for saving purposes.
894
+ - `usetensorboard`: Boolean flag to enable TensorBoard logging.
895
+ - `num_pretrain_epochs`: Number of epochs for pretraining phase.
896
+ - `num_epochs`: Total number of training epochs.
897
+ - `savemodel()`: Method to save the trained model.
898
+
899
+ Returns
900
+ -------
901
+ None
902
+ This function does not return any value.
903
+
904
+ Notes
905
+ -----
906
+ - If `self.usetensorboard` is True, TensorBoard logging is enabled.
907
+ - If `self.num_pretrain_epochs` is greater than 0, a pretraining phase is performed
908
+ before the main training loop.
909
+ - The model is saved after training using the `savemodel()` method.
910
+ - Training uses `ModelCheckpoint`, `EarlyStopping`, and `TerminateOnNaN` callbacks
911
+ to manage training process and prevent overfitting or NaN issues.
912
+
913
+ Examples
914
+ --------
915
+ >>> trainer = ModelTrainer(model, train_x, train_y, val_x, val_y)
916
+ >>> trainer.train()
917
+ """
423
918
  self.intermediatemodelpath = os.path.join(
424
- self.modelname, "model_e{epoch:02d}_v{val_loss:.4f}.h5"
919
+ self.modelname, "model_e{epoch:02d}_v{val_loss:.4f}.keras"
920
+ )
921
+ train_dataset = (
922
+ tf.data.Dataset.from_tensor_slices((self.train_x, self.train_y))
923
+ .shuffle(2048)
924
+ .batch(1024)
425
925
  )
926
+ val_dataset = tf.data.Dataset.from_tensor_slices((self.val_x, self.val_y)).batch(1024)
426
927
  if self.usetensorboard:
427
928
  tensorboard = TensorBoard(
428
- log_dir=self.intermediatemodelpath + "logs/{}".format(time())
929
+ log_dir=os.path.join(self.intermediatemodelpath, "logs", str(int(time.time())))
429
930
  )
430
931
  self.model.fit(self.train_x, self.train_y, verbose=1, callbacks=[tensorboard])
431
932
  else:
432
933
  if self.num_pretrain_epochs > 0:
433
934
  LGR.info("pretraining model to reproduce input data")
434
935
  self.history = self.model.fit(
435
- self.train_y,
436
- self.train_y,
437
- batch_size=1024,
936
+ train_dataset,
937
+ validation_data=val_dataset,
438
938
  epochs=self.num_pretrain_epochs,
439
- shuffle=True,
440
939
  verbose=1,
441
940
  callbacks=[
442
941
  TerminateOnNaN(),
443
- ModelCheckpoint(self.intermediatemodelpath),
942
+ ModelCheckpoint(self.intermediatemodelpath, save_format="keras"),
943
+ EarlyStopping(
944
+ monitor="val_loss", # or 'val_mae', etc.
945
+ patience=10, # number of epochs to wait
946
+ restore_best_weights=True,
947
+ ),
444
948
  ],
445
- validation_data=(self.val_y, self.val_y),
446
949
  )
447
950
  self.history = self.model.fit(
448
- self.train_x,
449
- self.train_y,
450
- batch_size=1024,
951
+ train_dataset,
952
+ validation_data=val_dataset,
451
953
  epochs=self.num_epochs,
452
- shuffle=True,
453
954
  verbose=1,
454
955
  callbacks=[
455
956
  TerminateOnNaN(),
456
- ModelCheckpoint(self.intermediatemodelpath),
957
+ ModelCheckpoint(self.intermediatemodelpath, save_format="keras"),
958
+ EarlyStopping(
959
+ monitor="val_loss", # or 'val_mae', etc.
960
+ patience=10, # number of epochs to wait
961
+ restore_best_weights=True,
962
+ ),
457
963
  ],
458
- validation_data=(self.val_x, self.val_y),
459
964
  )
460
- self.savemodel(usehdf=True)
461
- self.savemodel(usehdf=False)
965
+ self.savemodel()
462
966
  self.trained = True
463
967
 
464
- def apply(self, inputdata, badpts=None):
968
+ def apply(self, inputdata: NDArray, badpts: NDArray | None = None) -> NDArray:
969
+ """
970
+ Apply a sliding-window prediction model to the input data, optionally incorporating bad points.
971
+
972
+ This function performs a sliding-window prediction using a pre-trained model. It scales the input
973
+ data using the median absolute deviation (MAD), applies the model to overlapping windows of data,
974
+ and aggregates predictions with a weighted scheme. Optionally, bad points can be included in
975
+ the prediction process to influence the model's behavior.
976
+
977
+ Parameters
978
+ ----------
979
+ inputdata : NDArray
980
+ Input data array of shape (N,) to be processed.
981
+ badpts : NDArray | None, optional
982
+ Array of same shape as `inputdata` indicating bad or invalid points. If None, no bad points
983
+ are considered. Default is None.
984
+
985
+ Returns
986
+ -------
987
+ NDArray
988
+ Predicted data array of the same shape as `inputdata`, with predictions aggregated and
989
+ weighted across overlapping windows.
990
+
991
+ Notes
992
+ -----
993
+ - The function uses a sliding window of size `self.window_size` to process input data.
994
+ - Predictions are aggregated by summing over overlapping windows.
995
+ - A triangular weight scheme is applied to the aggregated predictions to reduce edge effects.
996
+ - If `self.usebadpts` is True, `badpts` are included as an additional feature in the model input.
997
+
998
+ Examples
999
+ --------
1000
+ >>> model = MyModel(window_size=10, usebadpts=True)
1001
+ >>> input_data = np.random.randn(100)
1002
+ >>> bad_points = np.zeros_like(input_data)
1003
+ >>> result = model.apply(input_data, bad_points)
1004
+ """
465
1005
  initscale = mad(inputdata)
466
1006
  scaleddata = inputdata / initscale
467
- predicteddata = scaleddata * 0.0
468
- weightarray = scaleddata * 0.0
1007
+ predicteddata = np.zeros_like(scaleddata)
1008
+ weightarray = np.zeros_like(scaleddata)
469
1009
  N_pts = len(scaleddata)
470
1010
  if self.usebadpts:
471
1011
  if badpts is None:
472
- badpts = scaleddata * 0.0
1012
+ badpts = np.zeros_like(scaleddata)
473
1013
  X = np.zeros(((N_pts - self.window_size - 1), self.window_size, 2))
474
1014
  for i in range(X.shape[0]):
475
1015
  X[i, :, 0] = scaleddata[i : i + self.window_size]
@@ -479,7 +1019,7 @@ class DeepLearningFilter:
479
1019
  for i in range(X.shape[0]):
480
1020
  X[i, :, 0] = scaleddata[i : i + self.window_size]
481
1021
 
482
- Y = self.model.predict(X)
1022
+ Y = self.predict_model(X).numpy()
483
1023
  for i in range(X.shape[0]):
484
1024
  predicteddata[i : i + self.window_size] += Y[i, :, 0]
485
1025
 
@@ -500,14 +1040,104 @@ class MultiscaleCNNDLFilter(DeepLearningFilter):
500
1040
  # it takes a time series as an input, performs 1-D convolution, and returns it as an output ready for concatenation
501
1041
  def __init__(
502
1042
  self,
503
- num_filters=10,
504
- kernel_sizes=[4, 8, 12],
505
- input_lens=[64, 128, 192],
506
- input_width=1,
507
- dilation_rate=1,
1043
+ num_filters: int = 10,
1044
+ kernel_sizes: list[int] = [4, 8, 12],
1045
+ input_lens: list[int] = [64, 128, 192],
1046
+ input_width: int = 1,
1047
+ dilation_rate: int = 1,
508
1048
  *args,
509
1049
  **kwargs,
510
- ):
1050
+ ) -> None:
1051
+ """
1052
+ Initialize the MultiscaleCNNDLFilter.
1053
+
1054
+ This constructor initializes a multiscale CNN filter with specified parameters
1055
+ for processing sequential data with multiple kernel sizes and dilation rates.
1056
+
1057
+ Parameters
1058
+ ----------
1059
+ num_filters : int, optional
1060
+ Number of filters to use in the convolutional layers. Default is 10.
1061
+ kernel_sizes : list of int, optional
1062
+ List of kernel sizes to use for different convolutional layers.
1063
+ Default is [4, 8, 12].
1064
+ input_lens : list of int, optional
1065
+ List of input sequence lengths to process. Default is [64, 128, 192].
1066
+ input_width : int, optional
1067
+ Width of the input data (number of input channels). Default is 1.
1068
+ dilation_rate : int, optional
1069
+ Dilation rate for the convolutional layers. Default is 1.
1070
+ *args
1071
+ Variable length argument list passed to parent class.
1072
+ **kwargs
1073
+ Arbitrary keyword arguments passed to parent class.
1074
+
1075
+ Returns
1076
+ -------
1077
+ None
1078
+ This method initializes the object and does not return any value.
1079
+
1080
+ Notes
1081
+ -----
1082
+ The initialized object will store network configuration information in
1083
+ `infodict` including network type, number of filters, kernel sizes, input lengths,
1084
+ and input width. The parent class initialization is called using `super()`.
1085
+
1086
+ Examples
1087
+ --------
1088
+ >>> filter = MultiscaleCNNDLFilter(
1089
+ ... num_filters=20,
1090
+ ... kernel_sizes=[3, 6, 9],
1091
+ ... input_lens=[32, 64, 128],
1092
+ ... input_width=2,
1093
+ ... dilation_rate=2
1094
+ ... )
1095
+ """
1096
+ """
1097
+ Initialize the MultiscaleCNNDLFilter.
1098
+
1099
+ This constructor initializes a multiscale CNN filter with specified parameters
1100
+ for processing sequential data with multiple kernel sizes and dilation rates.
1101
+
1102
+ Parameters
1103
+ ----------
1104
+ num_filters : int, optional
1105
+ Number of filters to use in the convolutional layers, default is 10
1106
+ kernel_sizes : list of int, optional
1107
+ List of kernel sizes to use for different convolutional layers,
1108
+ default is [4, 8, 12]
1109
+ input_lens : list of int, optional
1110
+ List of input sequence lengths to process, default is [64, 128, 192]
1111
+ input_width : int, optional
1112
+ Width of the input data (number of input channels), default is 1
1113
+ dilation_rate : int, optional
1114
+ Dilation rate for the convolutional layers, default is 1
1115
+ *args
1116
+ Variable length argument list passed to parent class
1117
+ **kwargs
1118
+ Arbitrary keyword arguments passed to parent class
1119
+
1120
+ Returns
1121
+ -------
1122
+ None
1123
+ This method initializes the object and does not return any value
1124
+
1125
+ Notes
1126
+ -----
1127
+ The initialized object will store network configuration information in
1128
+ `infodict` including network type, number of filters, kernel sizes, input lengths,
1129
+ and input width. The parent class initialization is called using super().
1130
+
1131
+ Examples
1132
+ --------
1133
+ >>> filter = MultiscaleCNNDLFilter(
1134
+ ... num_filters=20,
1135
+ ... kernel_sizes=[3, 6, 9],
1136
+ ... input_lens=[32, 64, 128],
1137
+ ... input_width=2,
1138
+ ... dilation_rate=2
1139
+ ... )
1140
+ """
511
1141
  self.num_filters = num_filters
512
1142
  self.kernel_sizes = kernel_sizes
513
1143
  self.input_lens = input_lens
@@ -521,16 +1151,81 @@ class MultiscaleCNNDLFilter(DeepLearningFilter):
521
1151
  super(MultiscaleCNNDLFilter, self).__init__(*args, **kwargs)
522
1152
 
523
1153
  def getname(self):
1154
+ """
1155
+ Generate and return model name based on configuration parameters.
1156
+
1157
+ This method constructs a descriptive model name by joining various configuration
1158
+ parameters with specific prefixes and zero-padded numbers. The generated name
1159
+ is used to create a unique model identifier and corresponding directory path.
1160
+
1161
+ Parameters
1162
+ ----------
1163
+ self : object
1164
+ The instance of the class containing the following attributes:
1165
+
1166
+ - window_size : int
1167
+ Size of the input window
1168
+ - num_layers : int
1169
+ Number of layers in the model
1170
+ - num_filters : int
1171
+ Number of filters in the model
1172
+ - kernel_size : int
1173
+ Size of the convolutional kernel
1174
+ - num_epochs : int
1175
+ Number of training epochs
1176
+ - excludethresh : float
1177
+ Threshold for excluding data points
1178
+ - corrthresh_rp : float
1179
+ Correlation threshold for filtering
1180
+ - step : int
1181
+ Step size for processing
1182
+ - dilation_rate : int
1183
+ Dilation rate for convolutional layers
1184
+ - activation : str
1185
+ Activation function name
1186
+ - usebadpts : bool
1187
+ Whether to use bad points in training
1188
+ - excludebysubject : bool
1189
+ Whether to exclude data by subject
1190
+ - namesuffix : str, optional
1191
+ Additional suffix to append to the model name
1192
+ - modelroot : str
1193
+ Root directory for model storage
1194
+
1195
+ Returns
1196
+ -------
1197
+ None
1198
+ This method modifies the instance attributes `modelname` and `modelpath`
1199
+ but does not return any value.
1200
+
1201
+ Notes
1202
+ -----
1203
+ The generated model name follows this format:
1204
+ "model_multiscalecnn_tf2_wXxx_lYy_fnZz_flZz_eXxx_tY_ctZ_sZ_dZ_activation[_usebadpts][_excludebysubject][_suffix]"
1205
+
1206
+ Where Xxx, Yy, Zz, etc. represent zero-padded numbers based on the parameter values.
1207
+
1208
+ Examples
1209
+ --------
1210
+ >>> model = MyModel()
1211
+ >>> model.window_size = 100
1212
+ >>> model.num_layers = 5
1213
+ >>> model.getname()
1214
+ >>> print(model.modelname)
1215
+ 'model_multiscalecnn_tf2_w100_l05_fn05_fl05_e001_t0.5_ct0.8_s1_d1_relu'
1216
+ """
524
1217
  self.modelname = "_".join(
525
1218
  [
526
1219
  "model",
527
1220
  "multiscalecnn",
528
- "w" + str(self.window_size),
529
- "l" + str(self.num_layers),
530
- "fn" + str(self.num_filters),
531
- "fl" + str(self.kernel_size),
532
- "e" + str(self.num_epochs),
1221
+ "tf2",
1222
+ "w" + str(self.window_size).zfill(3),
1223
+ "l" + str(self.num_layers).zfill(2),
1224
+ "fn" + str(self.num_filters).zfill(2),
1225
+ "fl" + str(self.kernel_size).zfill(2),
1226
+ "e" + str(self.num_epochs).zfill(3),
533
1227
  "t" + str(self.excludethresh),
1228
+ "ct" + str(self.corrthresh_rp),
534
1229
  "s" + str(self.step),
535
1230
  "d" + str(self.dilation_rate),
536
1231
  self.activation,
@@ -550,13 +1245,48 @@ class MultiscaleCNNDLFilter(DeepLearningFilter):
550
1245
  pass
551
1246
 
552
1247
  def makesubnet(self, inputlen, kernelsize):
1248
+ """
1249
+ Create a 1D convolutional neural network submodel for time series processing.
1250
+
1251
+ This function constructs a neural network submodel that processes time series data
1252
+ through 1D convolutional layers followed by global max pooling and dense layers
1253
+ with dropout regularization. The model is designed for feature extraction from
1254
+ sequential data.
1255
+
1256
+ Parameters
1257
+ ----------
1258
+ inputlen : int
1259
+ Length of the input time series sequence.
1260
+ kernelsize : int
1261
+ Size of the convolutional kernel for 1D convolution operation.
1262
+
1263
+ Returns
1264
+ -------
1265
+ Model
1266
+ Keras Model object representing the constructed submodel with the following structure:
1267
+ Input -> Conv1D -> GlobalMaxPool1D -> Dense -> Dropout -> Dense -> Output
1268
+
1269
+ Notes
1270
+ -----
1271
+ The model architecture includes:
1272
+ - 1D convolution with tanh activation
1273
+ - Global max pooling for sequence reduction
1274
+ - Two dense layers with tanh activation
1275
+ - Dropout regularization (0.3) after first dense layer
1276
+ - Uses 'same' padding for convolutional layer
1277
+
1278
+ Examples
1279
+ --------
1280
+ >>> model = makesubnet(inputlen=100, kernelsize=3)
1281
+ >>> model.summary()
1282
+ """
553
1283
  # the input is a time series of length input_len and width input_width
554
1284
  input_seq = Input(shape=(inputlen, self.input_width))
555
1285
 
556
1286
  # 1-D convolution and global max-pooling
557
- convolved = Conv1D(self.num_filters, kernelsize, padding="same", activation="tanh")(
558
- input_seq
559
- )
1287
+ convolved = Convolution1D(
1288
+ filters=self.num_filters, kernel_size=kernelsize, padding="same", activation="tanh"
1289
+ )(input_seq)
560
1290
  processed = GlobalMaxPool1D()(convolved)
561
1291
 
562
1292
  # dense layer with dropout regularization
@@ -566,6 +1296,48 @@ class MultiscaleCNNDLFilter(DeepLearningFilter):
566
1296
  return basemodel
567
1297
 
568
1298
  def makenet(self):
1299
+ """
1300
+ Create a multi-scale neural network for time series analysis.
1301
+
1302
+ This function constructs a neural network model that processes time series data at
1303
+ multiple resolutions (original, medium, and small scale). The model uses separate
1304
+ sub-networks for each resolution level and concatenates their outputs to make
1305
+ predictions. The architecture leverages different kernel sizes for different
1306
+ down-sampled versions to capture features at multiple temporal scales.
1307
+
1308
+ Parameters
1309
+ ----------
1310
+ self : object
1311
+ The instance containing the following attributes:
1312
+ - inputs_lens : list of int
1313
+ Lengths of input sequences for small, medium, and original scales.
1314
+ - input_width : int
1315
+ Width of input features.
1316
+ - kernel_sizes : list of int
1317
+ Kernel sizes for convolutional layers corresponding to each scale.
1318
+ - makesubnet : callable
1319
+ Function to create sub-network for a given sequence length and kernel size.
1320
+
1321
+ Returns
1322
+ -------
1323
+ None
1324
+ This method modifies the instance in-place by setting the `model` attribute
1325
+ to the constructed Keras model.
1326
+
1327
+ Notes
1328
+ -----
1329
+ The model architecture:
1330
+ 1. Takes three inputs at different resolutions.
1331
+ 2. Processes each input through separate sub-networks with scale-specific kernels.
1332
+ 3. Concatenates the embeddings from all branches.
1333
+ 4. Applies a final dense layer with sigmoid activation for binary classification.
1334
+
1335
+ Examples
1336
+ --------
1337
+ >>> # Assuming self is an instance with proper attributes set
1338
+ >>> self.makenet()
1339
+ >>> print(self.model.summary())
1340
+ """
569
1341
  # the inputs to the branches are the original time series, and its down-sampled versions
570
1342
  input_smallseq = Input(shape=(self.inputs_lens[0], self.input_width))
571
1343
  input_medseq = Input(shape=(self.inputs_lens[1], self.input_width))
@@ -587,7 +1359,48 @@ class MultiscaleCNNDLFilter(DeepLearningFilter):
587
1359
 
588
1360
 
589
1361
  class CNNDLFilter(DeepLearningFilter):
590
- def __init__(self, num_filters=10, kernel_size=5, dilation_rate=1, *args, **kwargs):
1362
+ def __init__(
1363
+ self,
1364
+ num_filters: int = 10,
1365
+ kernel_size: int = 5,
1366
+ dilation_rate: int = 1,
1367
+ *args,
1368
+ **kwargs,
1369
+ ) -> None:
1370
+ """
1371
+ Initialize the CNNDLFilter layer.
1372
+
1373
+ Parameters
1374
+ ----------
1375
+ num_filters : int, optional
1376
+ Number of convolutional filters to use, by default 10.
1377
+ kernel_size : int, optional
1378
+ Size of the convolutional kernel, by default 5.
1379
+ dilation_rate : int, optional
1380
+ Dilation rate for the convolutional layer, by default 1.
1381
+ *args
1382
+ Variable length argument list passed to parent class.
1383
+ **kwargs
1384
+ Arbitrary keyword arguments passed to parent class.
1385
+
1386
+ Returns
1387
+ -------
1388
+ None
1389
+ This method initializes the layer and does not return any value.
1390
+
1391
+ Notes
1392
+ -----
1393
+ This constructor sets up a convolutional layer with specified parameters
1394
+ and registers the network type as "cnn" in the infodict. The dilation rate
1395
+ controls the spacing between kernel points, allowing for wider receptive
1396
+ fields without increasing the number of parameters.
1397
+
1398
+ Examples
1399
+ --------
1400
+ >>> layer = CNNDLFilter(num_filters=32, kernel_size=3, dilation_rate=2)
1401
+ >>> print(layer.num_filters)
1402
+ 32
1403
+ """
591
1404
  self.num_filters = num_filters
592
1405
  self.kernel_size = kernel_size
593
1406
  self.dilation_rate = dilation_rate
@@ -597,16 +1410,86 @@ class CNNDLFilter(DeepLearningFilter):
597
1410
  super(CNNDLFilter, self).__init__(*args, **kwargs)
598
1411
 
599
1412
  def getname(self):
1413
+ """
1414
+ Generate and return the model name based on configuration parameters.
1415
+
1416
+ This method constructs a descriptive model name by joining various configuration
1417
+ parameters with specific prefixes and zero-padded numbers. The resulting name
1418
+ is used to create a unique directory path for model storage.
1419
+
1420
+ Parameters
1421
+ ----------
1422
+ self : object
1423
+ The instance of the class containing model configuration parameters.
1424
+ Expected attributes include:
1425
+ - window_size : int
1426
+ - num_layers : int
1427
+ - num_filters : int
1428
+ - kernel_size : int
1429
+ - num_epochs : int
1430
+ - excludethresh : float
1431
+ - corrthresh_rp : float
1432
+ - step : int
1433
+ - dilation_rate : int
1434
+ - activation : str
1435
+ - modelroot : str
1436
+ - usebadpts : bool
1437
+ - excludebysubject : bool
1438
+ - namesuffix : str, optional
1439
+
1440
+ Returns
1441
+ -------
1442
+ None
1443
+ This method does not return a value but sets the following attributes:
1444
+ - `self.modelname`: str, the constructed model name
1445
+ - `self.modelpath`: str, the full path to the model directory
1446
+
1447
+ Notes
1448
+ -----
1449
+ The generated model name follows this format:
1450
+ "model_cnn_tf2_wXXX_lYY_fnZZ_flZZ_eXXX_tY_ctZ_sZ_dZ_activation[_usebadpts][_excludebysubject][_suffix]"
1451
+
1452
+ Where:
1453
+ - XXX: window_size (3-digit zero-padded)
1454
+ - YY: num_layers (2-digit zero-padded)
1455
+ - ZZ: num_filters (2-digit zero-padded)
1456
+ - ZZ: kernel_size (2-digit zero-padded)
1457
+ - XXX: num_epochs (3-digit zero-padded)
1458
+ - Y: excludethresh (single digit)
1459
+ - Z: corrthresh_rp (single digit)
1460
+ - Z: step (single digit)
1461
+ - Z: dilation_rate (single digit)
1462
+
1463
+ Examples
1464
+ --------
1465
+ >>> model = MyModel()
1466
+ >>> model.window_size = 100
1467
+ >>> model.num_layers = 5
1468
+ >>> model.num_filters = 32
1469
+ >>> model.kernel_size = 3
1470
+ >>> model.num_epochs = 1000
1471
+ >>> model.excludethresh = 0.5
1472
+ >>> model.corrthresh_rp = 0.8
1473
+ >>> model.step = 1
1474
+ >>> model.dilation_rate = 2
1475
+ >>> model.activation = "relu"
1476
+ >>> model.modelroot = "./models"
1477
+ >>> model.getname()
1478
+ >>> print(model.modelname)
1479
+ 'model_cnn_tf2_w100_l05_fn32_fl03_e1000_t05_ct08_s1_d2_relu'
1480
+ """
600
1481
  self.modelname = "_".join(
601
1482
  [
602
1483
  "model",
603
1484
  "cnn",
604
- "w" + str(self.window_size),
605
- "l" + str(self.num_layers),
606
- "fn" + str(self.num_filters),
607
- "fl" + str(self.kernel_size),
608
- "e" + str(self.num_epochs),
1485
+ "tf2",
1486
+ "w" + str(self.window_size).zfill(3),
1487
+ "l" + str(self.num_layers).zfill(2),
1488
+ "fn" + str(self.num_filters).zfill(2),
1489
+ "fl" + str(self.kernel_size).zfill(2),
1490
+ "e" + str(self.num_epochs).zfill(3),
609
1491
  "t" + str(self.excludethresh),
1492
+ "ct" + str(self.corrthresh_rp),
610
1493
  "s" + str(self.step),
611
1494
  "d" + str(self.dilation_rate),
612
1495
  self.activation,
@@ -626,6 +1509,63 @@ class CNNDLFilter(DeepLearningFilter):
626
1509
  pass
627
1510
 
628
1511
  def makenet(self):
1512
+ """
1513
+ Create and configure a 1D convolutional neural network model.
1514
+
1515
+ This method builds a sequential CNN architecture with multiple convolutional layers,
1516
+ batch normalization, dropout regularization, and ReLU activation functions. The network
1517
+ is designed for sequence-to-sequence mapping with skip connections.
1518
+
1519
+ Parameters
1520
+ ----------
1521
+ self : object
1522
+ The instance of the class containing the model configuration parameters.
1523
+ Expected attributes include:
1524
+ - num_filters : int
1525
+ Number of convolutional filters in each layer.
1526
+ - kernel_size : int
1527
+ Size of the convolutional kernel.
1528
+ - inputsize : int
1529
+ Size of the input sequence.
1530
+ - num_layers : int
1531
+ Total number of layers in the network.
1532
+ - dilation_rate : int
1533
+ Dilation rate for dilated convolutions.
1534
+ - dropout_rate : float
1535
+ Dropout rate for regularization.
1536
+ - activation : str or callable
1537
+ Activation function to use.
1538
+
1539
+ Returns
1540
+ -------
1541
+ None
1542
+ This method modifies the instance's model attribute in-place and does not return anything.
1543
+
1544
+ Notes
1545
+ -----
1546
+ The network architecture follows this pattern:
1547
+ - Input layer with Conv1D, BatchNormalization, Dropout, and Activation
1548
+ - Intermediate layers with Conv1D, BatchNormalization, Dropout, and Activation
1549
+ - Output layer with Conv1D matching the input size
1550
+ - Model compiled with RMSprop optimizer and MSE loss
1551
+
1552
+ Examples
1553
+ --------
1554
+ >>> class MyModel:
1555
+ ... def __init__(self):
1556
+ ... self.num_filters = 64
1557
+ ... self.kernel_size = 3
1558
+ ... self.inputsize = 100
1559
+ ... self.num_layers = 5
1560
+ ... self.dilation_rate = 2
1561
+ ... self.dropout_rate = 0.2
1562
+ ... self.activation = 'relu'
1563
+ ... self.model = None
1564
+ ...
1565
+ >>> model = MyModel()
1566
+ >>> model.makenet()
1567
+ >>> print(model.model.summary())
1568
+ """
629
1569
  self.model = Sequential()
630
1570
 
631
1571
  # make the input layer
@@ -663,21 +1603,113 @@ class CNNDLFilter(DeepLearningFilter):
663
1603
 
664
1604
 
665
1605
  class DenseAutoencoderDLFilter(DeepLearningFilter):
666
- def __init__(self, encoding_dim=10, *args, **kwargs):
1606
+ def __init__(self, encoding_dim: int = 10, *args, **kwargs) -> None:
1607
+ """
1608
+ Initialize the DenseAutoencoderDLFilter.
1609
+
1610
+ Parameters
1611
+ ----------
1612
+ encoding_dim : int, default=10
1613
+ The dimensionality of the encoding layer in the autoencoder.
1614
+ *args
1615
+ Variable length argument list passed to the parent class constructor.
1616
+ **kwargs
1617
+ Arbitrary keyword arguments passed to the parent class constructor.
1618
+
1619
+ Returns
1620
+ -------
1621
+ None
1622
+ This method initializes the instance and does not return any value.
1623
+
1624
+ Notes
1625
+ -----
1626
+ This constructor sets up the autoencoder architecture by:
1627
+ 1. Storing the encoding dimension as an instance attribute
1628
+ 2. Updating the infodict with network type and encoding dimension information
1629
+ 3. Calling the parent class constructor with passed arguments
1630
+
1631
+ Examples
1632
+ --------
1633
+ >>> filter = DenseAutoencoderDLFilter(encoding_dim=20)
1634
+ >>> print(filter.encoding_dim)
1635
+ 20
1636
+ """
667
1637
  self.encoding_dim = encoding_dim
668
1638
  self.infodict["nettype"] = "autoencoder"
669
1639
  self.infodict["encoding_dim"] = self.encoding_dim
670
1640
  super(DenseAutoencoderDLFilter, self).__init__(*args, **kwargs)
671
1641
 
672
1642
  def getname(self):
1643
+ """
1644
+ Generate and return model name based on configuration parameters.
1645
+
1646
+ This method constructs a descriptive model name by joining various configuration
1647
+ parameters with specific prefixes and formatting conventions. The generated name
1648
+ is used to create a unique identifier for the model and its corresponding directory
1649
+ path.
1650
+
1651
+ Parameters
1652
+ ----------
1653
+ self : object
1654
+ The instance of the class containing the model configuration attributes.
1655
+ Expected attributes include:
1656
+ - `window_size`: int, size of the window
1657
+ - `encoding_dim`: int, dimension of the encoding layer
1658
+ - `num_epochs`: int, number of training epochs
1659
+ - `excludethresh`: float, threshold for exclusion
1660
+ - `corrthresh_rp`: float, correlation threshold
1661
+ - `step`: int, step size
1662
+ - `activation`: str, activation function name
1663
+ - `modelroot`: str, root directory for models
1664
+ - `usebadpts`: bool, flag to include bad points
1665
+ - `excludebysubject`: bool, flag to exclude by subject
1666
+ - `namesuffix`: str, optional suffix to append to the model name
1667
+
1668
+ Returns
1669
+ -------
1670
+ None
1671
+ This method does not return a value but sets the following attributes:
1672
+ - `self.modelname`: str, the generated model name
1673
+ - `self.modelpath`: str, the full path to the model directory
1674
+
1675
+ Notes
1676
+ -----
1677
+ The model name is constructed using the following components:
1678
+ - "model_denseautoencoder_tf2" as base identifier
1679
+ - Window size with 3-digit zero-padded formatting (wXXX)
1680
+ - Encoding dimension with 3-digit zero-padded formatting (enXXX)
1681
+ - Number of epochs with 3-digit zero-padded formatting (eXXX)
1682
+ - Exclusion threshold (tX.XX)
1683
+ - Correlation threshold (ctX.XX)
1684
+ - Step size (sX)
1685
+ - Activation function name
1686
+ - Optional suffixes based on configuration flags
1687
+
1688
+ Examples
1689
+ --------
1690
+ >>> model = MyModel()
1691
+ >>> model.window_size = 100
1692
+ >>> model.encoding_dim = 50
1693
+ >>> model.num_epochs = 1000
1694
+ >>> model.excludethresh = 0.5
1695
+ >>> model.corrthresh_rp = 0.8
1696
+ >>> model.step = 10
1697
+ >>> model.activation = 'relu'
1698
+ >>> model.modelroot = '/models'
1699
+ >>> model.getname()
1700
+ >>> print(model.modelname)
1701
+ 'model_denseautoencoder_tf2_w100_en050_e1000_t0.5_ct00.8_s10_relu'
1702
+ """
673
1703
  self.modelname = "_".join(
674
1704
  [
675
1705
  "model",
676
1706
  "denseautoencoder",
677
- "w" + str(self.window_size),
678
- "en" + str(self.encoding_dim),
679
- "e" + str(self.num_epochs),
1707
+ "tf2",
1708
+ "w" + str(self.window_size).zfill(3),
1709
+ "en" + str(self.encoding_dim).zfill(3),
1710
+ "e" + str(self.num_epochs).zfill(3),
680
1711
  "t" + str(self.excludethresh),
1712
+ "ct" + str(self.corrthresh_rp),
681
1713
  "s" + str(self.step),
682
1714
  self.activation,
683
1715
  ]
@@ -696,6 +1728,56 @@ class DenseAutoencoderDLFilter(DeepLearningFilter):
696
1728
  pass
697
1729
 
698
1730
  def makenet(self):
1731
+ """
1732
+ Create and compile a neural network model for autoencoding.
1733
+
1734
+ This function constructs a symmetric autoencoder architecture with configurable
1735
+ number of layers, encoding dimension, and activation function. The network
1736
+ consists of an input layer, multiple encoding layers, an encoding layer,
1737
+ decoding layers, and an output layer. Batch normalization, dropout, and
1738
+ activation functions are applied at each layer as specified by the instance
1739
+ attributes.
1740
+
1741
+ Parameters
1742
+ ----------
1743
+ self : object
1744
+ The instance of the class containing the following attributes:
1745
+ - num_layers : int
1746
+ Number of layers in the network.
1747
+ - encoding_dim : int
1748
+ Dimension of the encoding layer.
1749
+ - inputsize : int
1750
+ Size of the input data.
1751
+ - dropout_rate : float
1752
+ Dropout rate applied to all layers.
1753
+ - activation : str or callable
1754
+ Activation function used in all layers.
1755
+ - model : keras.Sequential
1756
+ The constructed Keras model (assigned within the function).
1757
+
1758
+ Returns
1759
+ -------
1760
+ None
1761
+ This function does not return a value but assigns the constructed model
1762
+ to the instance attribute `self.model`.
1763
+
1764
+ Notes
1765
+ -----
1766
+ - The network architecture is symmetric, with the number of units in each
1767
+ layer following a pattern that doubles or halves based on the layer index.
1768
+ - The model is compiled with the RMSprop optimizer and mean squared error loss.
1769
+
1770
+ Examples
1771
+ --------
1772
+ >>> autoencoder = AutoEncoder()
1773
+ >>> autoencoder.num_layers = 4
1774
+ >>> autoencoder.encoding_dim = 32
1775
+ >>> autoencoder.inputsize = 784
1776
+ >>> autoencoder.dropout_rate = 0.2
1777
+ >>> autoencoder.activation = 'relu'
1778
+ >>> autoencoder.makenet()
1779
+ >>> autoencoder.model.summary()
1780
+ """
699
1781
  self.model = Sequential()
700
1782
 
701
1783
  # make the input layer
@@ -742,8 +1824,51 @@ class DenseAutoencoderDLFilter(DeepLearningFilter):
742
1824
 
743
1825
  class ConvAutoencoderDLFilter(DeepLearningFilter):
744
1826
  def __init__(
745
- self, encoding_dim=10, num_filters=5, kernel_size=5, dilation_rate=1, *args, **kwargs
746
- ):
1827
+ self,
1828
+ encoding_dim: int = 10,
1829
+ num_filters: int = 5,
1830
+ kernel_size: int = 5,
1831
+ dilation_rate: int = 1,
1832
+ *args,
1833
+ **kwargs,
1834
+ ) -> None:
1835
+ """
1836
+ Initialize ConvAutoencoderDLFilter.
1837
+
1838
+ Parameters
1839
+ ----------
1840
+ encoding_dim : int, optional
1841
+ Dimension of the encoding layer, by default 10.
1842
+ num_filters : int, optional
1843
+ Number of filters in the convolutional layers, by default 5.
1844
+ kernel_size : int, optional
1845
+ Size of the convolutional kernel, by default 5.
1846
+ dilation_rate : int, optional
1847
+ Dilation rate for the convolutional layers, by default 1.
1848
+ *args
1849
+ Variable length argument list.
1850
+ **kwargs
1851
+ Arbitrary keyword arguments.
1852
+
1853
+ Returns
1854
+ -------
1855
+ None
1856
+ This method does not return any value.
1857
+
1858
+ Notes
1859
+ -----
1860
+ This constructor initializes the ConvAutoencoderDLFilter with specified
1861
+ convolutional parameters and sets up the infodict with network metadata.
1862
+
1863
+ Examples
1864
+ --------
1865
+ >>> model = ConvAutoencoderDLFilter(
1866
+ ... encoding_dim=15,
1867
+ ... num_filters=8,
1868
+ ... kernel_size=3,
1869
+ ... dilation_rate=2
1870
+ ... )
1871
+ """
747
1872
  self.encoding_dim = encoding_dim
748
1873
  self.num_filters = num_filters
749
1874
  self.kernel_size = kernel_size
@@ -755,16 +1880,79 @@ class ConvAutoencoderDLFilter(DeepLearningFilter):
755
1880
  super(ConvAutoencoderDLFilter, self).__init__(*args, **kwargs)
756
1881
 
757
1882
  def getname(self):
1883
+ """
1884
+ Generate and configure the model name and path based on current configuration parameters.
1885
+
1886
+ This method constructs a descriptive model name string using various configuration
1887
+ parameters and creates the corresponding directory path for model storage. The generated
1888
+ name includes information about window size, encoding dimensions, filter settings,
1889
+ training parameters, and optional flags.
1890
+
1891
+ Parameters
1892
+ ----------
1893
+ self : object
1894
+ The instance containing configuration parameters for model naming.
1895
+ Expected attributes include:
1896
+ - window_size : int
1897
+ - encoding_dim : int
1898
+ - num_filters : int
1899
+ - kernel_size : int
1900
+ - num_epochs : int
1901
+ - excludethresh : float
1902
+ - corrthresh_rp : float
1903
+ - step : int
1904
+ - activation : str
1905
+ - usebadpts : bool
1906
+ - excludebysubject : bool
1907
+ - namesuffix : str or None
1908
+ - modelroot : str
1909
+
1910
+ Returns
1911
+ -------
1912
+ None
1913
+ This method modifies the instance attributes in-place and does not return a value.
1914
+ Modifies the following instance attributes:
1915
+ - modelname : str
1916
+ - modelpath : str
1917
+
1918
+ Notes
1919
+ -----
1920
+ The generated model name follows a specific naming convention:
1921
+ "model_convautoencoder_tf2_wXXX_enYYY_fnZZ_flZZ_eXXX_tY_ctZ_sZ_activation"
1922
+ where XXX, YYY, ZZ, and Z represent zero-padded numerical values.
1923
+
1924
+ Examples
1925
+ --------
1926
+ >>> model = MyModel()
1927
+ >>> model.window_size = 100
1928
+ >>> model.encoding_dim = 50
1929
+ >>> model.num_filters = 32
1930
+ >>> model.kernel_size = 5
1931
+ >>> model.num_epochs = 1000
1932
+ >>> model.excludethresh = 0.5
1933
+ >>> model.corrthresh_rp = 0.8
1934
+ >>> model.step = 10
1935
+ >>> model.activation = 'relu'
1936
+ >>> model.usebadpts = True
1937
+ >>> model.excludebysubject = False
1938
+ >>> model.namesuffix = 'test'
1939
+ >>> model.modelroot = '/path/to/models'
1940
+ >>> model.getname()
1941
+ >>> print(model.modelname)
1942
+ 'model_convautoencoder_tf2_w100_en050_fn32_fl05_e1000_t0.5_ct0.8_s10_relu_usebadpts_test'
1943
+ """
758
1944
  self.modelname = "_".join(
759
1945
  [
760
1946
  "model",
761
1947
  "convautoencoder",
762
- "w" + str(self.window_size),
763
- "en" + str(self.encoding_dim),
764
- "fn" + str(self.num_filters),
765
- "fl" + str(self.kernel_size),
766
- "e" + str(self.num_epochs),
1948
+ "tf2",
1949
+ "w" + str(self.window_size).zfill(3),
1950
+ "en" + str(self.encoding_dim).zfill(3),
1951
+ "fn" + str(self.num_filters).zfill(2),
1952
+ "fl" + str(self.kernel_size).zfill(2),
1953
+ "e" + str(self.num_epochs).zfill(3),
767
1954
  "t" + str(self.excludethresh),
1955
+ "ct" + str(self.corrthresh_rp),
768
1956
  "s" + str(self.step),
769
1957
  self.activation,
770
1958
  ]
@@ -783,125 +1971,465 @@ class ConvAutoencoderDLFilter(DeepLearningFilter):
783
1971
  pass
784
1972
 
785
1973
  def makenet(self):
786
- self.model = Sequential()
787
-
788
- # make the input layer
789
- self.model.add(
790
- Convolution1D(
791
- filters=self.num_filters,
792
- kernel_size=self.kernel_size,
793
- padding="same",
794
- input_shape=(None, self.inputsize),
795
- )
1974
+ """
1975
+ Build and compile a 1D convolutional autoencoder model.
1976
+
1977
+ This function constructs a symmetric encoder-decoder architecture using 1D convolutions,
1978
+ batch normalization, dropout, and pooling layers. The model is designed for sequence
1979
+ processing tasks such as time-series or signal denoising.
1980
+
1981
+ Parameters
1982
+ ----------
1983
+ self : object
1984
+ Instance of the class containing the following attributes:
1985
+ - window_size : int
1986
+ The length of the input sequence.
1987
+ - inputsize : int
1988
+ The number of input features at each time step.
1989
+ - num_filters : int
1990
+ Initial number of filters in the first convolutional layer.
1991
+ - kernel_size : int
1992
+ Size of the convolutional kernel.
1993
+ - dropout_rate : float
1994
+ Dropout rate applied after batch normalization.
1995
+ - activation : str or callable
1996
+ Activation function used in layers.
1997
+ - encoding_dim : int
1998
+ Dimensionality of the encoded representation.
1999
+
2000
+ Returns
2001
+ -------
2002
+ None
2003
+ This method does not return a value but sets the `self.model` attribute to the
2004
+ compiled Keras model.
2005
+
2006
+ Notes
2007
+ -----
2008
+ The model architecture includes:
2009
+ - An initial convolutional block followed by max pooling.
2010
+ - Three encoding layers with increasing filter sizes and halving the sequence length.
2011
+ - A bottleneck layer that compresses the representation.
2012
+ - A symmetric decoding path that mirrors the encoding path.
2013
+ - Final upsampling to reconstruct the original sequence dimensions.
2014
+
2015
+ Examples
2016
+ --------
2017
+ >>> model = MyClass()
2018
+ >>> model.window_size = 100
2019
+ >>> model.inputsize = 10
2020
+ >>> model.num_filters = 32
2021
+ >>> model.kernel_size = 3
2022
+ >>> model.dropout_rate = 0.2
2023
+ >>> model.activation = 'relu'
2024
+ >>> model.encoding_dim = 16
2025
+ >>> model.makenet()
2026
+ >>> model.model.summary()
2027
+ """
2028
+ input_layer = Input(shape=(self.window_size, self.inputsize))
2029
+ x = input_layer
2030
+
2031
+ # Initial conv block
2032
+ x = Convolution1D(filters=self.num_filters, kernel_size=self.kernel_size, padding="same")(
2033
+ x
796
2034
  )
797
- self.model.add(BatchNormalization())
798
- self.model.add(Dropout(rate=self.dropout_rate))
799
- self.model.add(Activation(self.activation))
800
- self.model.add(MaxPooling1D(2, padding="same"))
2035
+ x = BatchNormalization()(x)
2036
+ x = Dropout(rate=self.dropout_rate)(x)
2037
+ x = Activation(self.activation)(x)
2038
+ x = MaxPooling1D(pool_size=2, padding="same")(x)
801
2039
 
802
- layersize = self.windowsize
2040
+ layersize = self.window_size
803
2041
  nfilters = self.num_filters
804
- num_encodinglayers = 3
805
- num_decodinglayers = 3
806
- layerprops = [(layersize, nfilters)]
807
- # make the encoding layers
808
- for i in range(num_encodinglayers):
809
- layersize = int(layersize // 2)
810
- nfilters *= 2
811
- LGR.info(f"input layer size: {layersize}, nfilters: {nfilters}")
812
- self.model.add(
813
- Convolution1D(filters=nfilters, kernel_size=self.kernel_size, padding="same")
814
- )
815
- self.model.add(BatchNormalization())
816
- self.model.add(Dropout(rate=self.dropout_rate))
817
- self.model.add(Activation(self.activation))
818
- self.model.add(MaxPooling1D(2, padding="same"))
2042
+ filter_list = []
819
2043
 
820
- # make the decoding layers
821
- for i in range(num_decodinglayers):
822
- self.model.add(UpSampling1D(2))
2044
+ # Encoding path (3 layers)
2045
+ for _ in range(3):
2046
+ layersize = int(np.ceil(layersize / 2))
2047
+ nfilters *= 2
2048
+ filter_list.append(nfilters)
2049
+ x = Convolution1D(filters=nfilters, kernel_size=self.kernel_size, padding="same")(x)
2050
+ x = BatchNormalization()(x)
2051
+ x = Dropout(rate=self.dropout_rate)(x)
2052
+ x = Activation(self.activation)(x)
2053
+ x = MaxPooling1D(pool_size=2, padding="same")(x)
2054
+
2055
+ # Save shape for reshaping later
2056
+ shape_before_flatten = K.int_shape(x)[1:] # (timesteps, channels)
2057
+
2058
+ # Bottleneck
2059
+ x = Flatten()(x)
2060
+ x = Dense(self.encoding_dim, activation=self.activation, name="encoded")(x)
2061
+ x = Dense(np.prod(shape_before_flatten), activation=self.activation)(x)
2062
+ x = Reshape(shape_before_flatten)(x)
2063
+
2064
+ # Decoding path (mirror)
2065
+ for filters in reversed(filter_list):
823
2066
  layersize *= 2
824
- nfilters = int(nfilters // 2)
825
- LGR.info(f"input layer size: {layersize}")
826
- self.model.add(
827
- Convolution1D(
828
- filters=self.num_filters,
829
- kernel_size=self.kernel_size,
830
- padding="same",
831
- )
832
- )
833
- self.model.add(BatchNormalization())
834
- self.model.add(Dropout(rate=self.dropout_rate))
835
- self.model.add(Activation(self.activation))
2067
+ x = UpSampling1D(size=2)(x)
2068
+ x = Convolution1D(filters=filters, kernel_size=self.kernel_size, padding="same")(x)
2069
+ x = BatchNormalization()(x)
2070
+ x = Dropout(rate=self.dropout_rate)(x)
2071
+ x = Activation(self.activation)(x)
2072
+
2073
+ # Final upsampling (to match initial maxpool)
2074
+ x = UpSampling1D(size=2)(x)
2075
+ x = Convolution1D(filters=self.inputsize, kernel_size=self.kernel_size, padding="same")(x)
2076
+
2077
+ output_layer = x
2078
+ self.model = Model(inputs=input_layer, outputs=output_layer)
2079
+ self.model.compile(optimizer="adam", loss="mse")
836
2080
 
837
- # make the intermediate encoding layers
838
- for i in range(1, self.num_layers - 1):
839
- LGR.info(f"input layer size: {layersize}")
840
- self.model.add(
841
- Convolution1D(
842
- filters=self.num_filters,
843
- kernel_size=self.kernel_size,
844
- padding="same",
845
- )
846
- )
847
- self.model.add(BatchNormalization())
848
- self.model.add(Dropout(rate=self.dropout_rate))
849
- self.model.add(Activation(self.activation))
850
- self.model.add(MaxPooling1D(2, padding="same"))
851
- layersize = int(layersize // 2)
852
2081
 
853
- # make the encoding layer
854
- LGR.info(f"input layer size: {layersize}")
855
- self.model.add(
856
- Convolution1D(filters=self.num_filters, kernel_size=self.kernel_size, padding="same")
2082
+ class CRNNDLFilter(DeepLearningFilter):
2083
+ def __init__(
2084
+ self,
2085
+ encoding_dim: int = 10,
2086
+ num_filters: int = 10,
2087
+ kernel_size: int = 5,
2088
+ dilation_rate: int = 1,
2089
+ *args,
2090
+ **kwargs,
2091
+ ) -> None:
2092
+ """
2093
+ Initialize CRNNDLFilter layer.
2094
+
2095
+ Parameters
2096
+ ----------
2097
+ encoding_dim : int, default=10
2098
+ Dimension of the encoding layer.
2099
+ num_filters : int, default=10
2100
+ Number of filters in the convolutional layer.
2101
+ kernel_size : int, default=5
2102
+ Size of the convolutional kernel.
2103
+ dilation_rate : int, default=1
2104
+ Dilation rate for the convolutional layer.
2105
+ *args
2106
+ Variable length argument list.
2107
+ **kwargs
2108
+ Arbitrary keyword arguments.
2109
+
2110
+ Returns
2111
+ -------
2112
+ None
2113
+ This method does not return any value.
2114
+
2115
+ Notes
2116
+ -----
2117
+ This constructor initializes the CRNNDLFilter layer with specified parameters
2118
+ and sets up the network type information in the infodict.
2119
+
2120
+ Examples
2121
+ --------
2122
+ >>> filter_layer = CRNNDLFilter(
2123
+ ... encoding_dim=15,
2124
+ ... num_filters=20,
2125
+ ... kernel_size=3,
2126
+ ... dilation_rate=2
2127
+ ... )
2128
+ """
2129
+ self.num_filters = num_filters
2130
+ self.kernel_size = kernel_size
2131
+ self.dilation_rate = dilation_rate
2132
+ self.encoding_dim = encoding_dim
2133
+ self.infodict["nettype"] = "cnn"
2134
+ self.infodict["num_filters"] = self.num_filters
2135
+ self.infodict["kernel_size"] = self.kernel_size
2136
+ self.infodict["encoding_dim"] = self.encoding_dim
2137
+ super(CRNNDLFilter, self).__init__(*args, **kwargs)
2138
+
2139
+ def getname(self):
2140
+ """
2141
+ Generate and configure the model name and path based on current parameters.
2142
+
2143
+ This method constructs a descriptive model name string using various instance
2144
+ attributes and creates the corresponding directory path for model storage.
2145
+
2146
+ Parameters
2147
+ ----------
2148
+ self : object
2149
+ The instance containing model configuration parameters
2150
+
2151
+ Attributes Used
2152
+ ---------------
2153
+ window_size : int
2154
+ Size of the sliding window
2155
+ encoding_dim : int
2156
+ Dimension of the encoding layer
2157
+ num_filters : int
2158
+ Number of filters in the convolutional layers
2159
+ kernel_size : int
2160
+ Size of the convolutional kernel
2161
+ num_epochs : int
2162
+ Number of training epochs
2163
+ excludethresh : float
2164
+ Threshold for excluding data points
2165
+ corrthresh_rp : float
2166
+ Correlation threshold for filtering
2167
+ step : int
2168
+ Step size for sliding window
2169
+ activation : str
2170
+ Activation function used
2171
+ usebadpts : bool
2172
+ Whether to use bad points in training
2173
+ excludebysubject : bool
2174
+ Whether to exclude data by subject
2175
+ namesuffix : str, optional
2176
+ Additional suffix to append to model name
2177
+ modelroot : str
2178
+ Root directory for model storage
2179
+
2180
+ Returns
2181
+ -------
2182
+ None
2183
+ This method modifies instance attributes in-place:
2184
+ - self.modelname: constructed model name string
2185
+ - self.modelpath: full path to model directory
2186
+
2187
+ Notes
2188
+ -----
2189
+ The generated model name follows a consistent format:
2190
+ "model_crnn_tf2_wXxx_enXxx_fnXX_flXX_eXXX_tX_ctX_sX_activation"
2191
+ where Xxx represents zero-padded numbers and XX represents zero-padded two-digit numbers.
2192
+
2193
+ Examples
2194
+ --------
2195
+ >>> model = MyModel()
2196
+ >>> model.window_size = 100
2197
+ >>> model.encoding_dim = 50
2198
+ >>> model.getname()
2199
+ >>> print(model.modelname)
2200
+ 'model_crnn_tf2_w100_en050_fn10_fl10_e001_t0.5_ct0.8_s1_relu'
2201
+ """
2202
+ self.modelname = "_".join(
2203
+ [
2204
+ "model",
2205
+ "crnn",
2206
+ "tf2",
2207
+ "w" + str(self.window_size).zfill(3),
2208
+ "en" + str(self.encoding_dim).zfill(3),
2209
+ "fn" + str(self.num_filters).zfill(2),
2210
+ "fl" + str(self.kernel_size).zfill(2),
2211
+ "e" + str(self.num_epochs).zfill(3),
2212
+ "t" + str(self.excludethresh),
2213
+ "ct" + str(self.corrthresh_rp),
2214
+ "s" + str(self.step),
2215
+ self.activation,
2216
+ ]
857
2217
  )
858
- self.model.add(BatchNormalization())
859
- self.model.add(Dropout(rate=self.dropout_rate))
860
- self.model.add(Activation(self.activation))
2218
+ if self.usebadpts:
2219
+ self.modelname += "_usebadpts"
2220
+ if self.excludebysubject:
2221
+ self.modelname += "_excludebysubject"
2222
+ if self.namesuffix is not None:
2223
+ self.modelname += "_" + self.namesuffix
2224
+ self.modelpath = os.path.join(self.modelroot, self.modelname)
861
2225
 
862
- # make the intermediate decoding layers
863
- for i in range(1, self.num_layers):
864
- self.model.add(UpSampling1D(2))
865
- layersize = layersize * 2
866
- LGR.info(f"input layer size: {layersize}")
867
- self.model.add(
868
- Convolution1D(
869
- filters=self.num_filters,
870
- kernel_size=self.kernel_size,
871
- padding="same",
872
- )
873
- )
874
- self.model.add(BatchNormalization())
875
- self.model.add(Dropout(rate=self.dropout_rate))
876
- self.model.add(Activation(self.activation))
2226
+ try:
2227
+ os.makedirs(self.modelpath)
2228
+ except OSError:
2229
+ pass
877
2230
 
878
- # make the output layer
879
- LGR.info(f"input layer size: {layersize}")
880
- self.model.add(
881
- Convolution1D(filters=self.inputsize, kernel_size=self.kernel_size, padding="same")
2231
+ def makenet(self):
2232
+ """
2233
+ Create and compile a 1D convolutional neural network for temporal feature extraction and reconstruction.
2234
+
2235
+ This function builds a neural network architecture consisting of:
2236
+ - A convolutional front-end for feature extraction
2237
+ - A bidirectional LSTM layer for temporal modeling
2238
+ - A dense output layer mapping to the input size
2239
+
2240
+ The model is compiled with Adam optimizer and mean squared error loss.
2241
+
2242
+ Parameters
2243
+ ----------
2244
+ self : object
2245
+ The class instance containing the following attributes:
2246
+ - window_size : int
2247
+ The size of the input time window.
2248
+ - inputsize : int
2249
+ The number of input channels/features.
2250
+ - num_filters : int
2251
+ Number of filters in the convolutional layers.
2252
+ - kernel_size : int
2253
+ Size of the convolutional kernel.
2254
+ - dropout_rate : float
2255
+ Dropout rate for regularization.
2256
+ - activation : str or callable
2257
+ Activation function for convolutional layers.
2258
+ - encoding_dim : int
2259
+ Number of units in the LSTM layer.
2260
+
2261
+ Returns
2262
+ -------
2263
+ None
2264
+ This method modifies the instance's `model` attribute in-place.
2265
+
2266
+ Notes
2267
+ -----
2268
+ The network architecture follows this pipeline:
2269
+ Input -> Conv1D -> BatchNorm -> Dropout -> Activation ->
2270
+ Conv1D -> BatchNorm -> Dropout -> Activation ->
2271
+ Bidirectional LSTM -> Dense -> Output
2272
+
2273
+ The model is compiled with:
2274
+ - Optimizer: Adam
2275
+ - Loss: Mean Squared Error (MSE)
2276
+
2277
+ Examples
2278
+ --------
2279
+ >>> # Assuming a class with the required attributes
2280
+ >>> model = MyModel()
2281
+ >>> model.window_size = 100
2282
+ >>> model.inputsize = 10
2283
+ >>> model.num_filters = 32
2284
+ >>> model.kernel_size = 3
2285
+ >>> model.dropout_rate = 0.2
2286
+ >>> model.activation = 'relu'
2287
+ >>> model.encoding_dim = 64
2288
+ >>> model.makenet()
2289
+ >>> model.model.summary()
2290
+ """
2291
+ input_layer = Input(shape=(self.window_size, self.inputsize))
2292
+ x = input_layer
2293
+
2294
+ # Convolutional front-end: feature extraction
2295
+ x = Convolution1D(filters=self.num_filters, kernel_size=self.kernel_size, padding="same")(
2296
+ x
882
2297
  )
2298
+ x = BatchNormalization()(x)
2299
+ x = Dropout(rate=self.dropout_rate)(x)
2300
+ x = Activation(self.activation)(x)
2301
+
2302
+ x = Convolution1D(
2303
+ filters=self.num_filters * 2, kernel_size=self.kernel_size, padding="same"
2304
+ )(x)
2305
+ x = BatchNormalization()(x)
2306
+ x = Dropout(rate=self.dropout_rate)(x)
2307
+ x = Activation(self.activation)(x)
2308
+
2309
+ # Recurrent layer: temporal modeling
2310
+ x = Bidirectional(LSTM(units=self.encoding_dim, return_sequences=True))(x)
2311
+
2312
+ # Output mapping to inputsize channels
2313
+ output_layer = Dense(self.inputsize)(x)
2314
+
2315
+ # Model definition
2316
+ self.model = Model(inputs=input_layer, outputs=output_layer)
883
2317
  self.model.compile(optimizer="adam", loss="mse")
884
2318
 
885
2319
 
886
2320
  class LSTMDLFilter(DeepLearningFilter):
887
- def __init__(self, num_units=16, *args, **kwargs):
2321
+ def __init__(self, num_units: int = 16, *args, **kwargs) -> None:
2322
+ """
2323
+ Initialize the LSTMDLFilter layer.
2324
+
2325
+ Parameters
2326
+ ----------
2327
+ num_units : int, optional
2328
+ Number of units in the LSTM layer, by default 16
2329
+ *args : tuple
2330
+ Additional positional arguments passed to the parent class
2331
+ **kwargs : dict
2332
+ Additional keyword arguments passed to the parent class
2333
+
2334
+ Returns
2335
+ -------
2336
+ None
2337
+ This method initializes the layer in-place and does not return any value
2338
+
2339
+ Notes
2340
+ -----
2341
+ This method sets up the LSTM layer with the specified number of units and
2342
+ configures the infodict with the network type and unit count. The parent
2343
+ class initialization is called with any additional arguments provided.
2344
+
2345
+ Examples
2346
+ --------
2347
+ >>> layer = LSTMDLFilter(num_units=32)
2348
+ >>> print(layer.num_units)
2349
+ 32
2350
+ """
888
2351
  self.num_units = num_units
889
2352
  self.infodict["nettype"] = "lstm"
890
2353
  self.infodict["num_units"] = self.num_units
891
2354
  super(LSTMDLFilter, self).__init__(*args, **kwargs)
892
2355
 
893
2356
  def getname(self):
2357
+ """
2358
+ Generate and return the model name and path based on current configuration parameters.
2359
+
2360
+ This method constructs a standardized model name string using various configuration
2361
+ parameters and creates the corresponding directory path. The generated name includes
2362
+ information about the model architecture, training parameters, and preprocessing settings.
2363
+
2364
+ Parameters
2365
+ ----------
2366
+ self : object
2367
+ The instance containing the following attributes:
2368
+ - window_size : int
2369
+ Size of the sliding window for time series data
2370
+ - num_layers : int
2371
+ Number of LSTM layers in the model
2372
+ - num_units : int
2373
+ Number of units in each LSTM layer
2374
+ - dropout_rate : float
2375
+ Dropout rate for regularization
2376
+ - num_epochs : int
2377
+ Number of training epochs
2378
+ - excludethresh : float
2379
+ Threshold for exclusion criteria
2380
+ - corrthresh_rp : float
2381
+ Correlation threshold for filtering
2382
+ - step : int
2383
+ Step size for data processing
2384
+ - excludebysubject : bool
2385
+ Whether to exclude data by subject
2386
+ - modelroot : str
2387
+ Root directory for model storage
2388
+
2389
+ Returns
2390
+ -------
2391
+ None
2392
+ This method modifies the instance attributes `modelname` and `modelpath` in place.
2393
+ It does not return any value.
2394
+
2395
+ Notes
2396
+ -----
2397
+ The generated model name follows a specific naming convention:
2398
+ "model_lstm_tf2_wXxx_lYY_nuZZZ_dDD_rdDD_eEEE_tT_ctTT_sS"
2399
+ where Xxx, YY, ZZZ, DD, EEEE, T, TT, S represent zero-padded numerical values.
2400
+
2401
+ If `excludebysubject` is True, "_excludebysubject" is appended to the model name.
2402
+
2403
+ Examples
2404
+ --------
2405
+ >>> model = MyModel()
2406
+ >>> model.window_size = 100
2407
+ >>> model.num_layers = 2
2408
+ >>> model.num_units = 128
2409
+ >>> model.dropout_rate = 0.2
2410
+ >>> model.num_epochs = 100
2411
+ >>> model.excludethresh = 0.5
2412
+ >>> model.corrthresh_rp = 0.8
2413
+ >>> model.step = 1
2414
+ >>> model.excludebysubject = True
2415
+ >>> model.modelroot = "/path/to/models"
2416
+ >>> model.getname()
2417
+ >>> print(model.modelname)
2418
+ 'model_lstm_tf2_w100_l02_nu128_d02_rd02_e100_t05_ct08_s1_excludebysubject'
2419
+ """
894
2420
  self.modelname = "_".join(
895
2421
  [
896
2422
  "model",
897
2423
  "lstm",
898
- "w" + str(self.window_size),
899
- "l" + str(self.num_layers),
2424
+ "tf2",
2425
+ "w" + str(self.window_size).zfill(3),
2426
+ "l" + str(self.num_layers).zfill(2),
900
2427
  "nu" + str(self.num_units),
901
2428
  "d" + str(self.dropout_rate),
902
2429
  "rd" + str(self.dropout_rate),
903
- "e" + str(self.num_epochs),
2430
+ "e" + str(self.num_epochs).zfill(3),
904
2431
  "t" + str(self.excludethresh),
2432
+ "ct" + str(self.corrthresh_rp),
905
2433
  "s" + str(self.step),
906
2434
  ]
907
2435
  )
@@ -915,6 +2443,47 @@ class LSTMDLFilter(DeepLearningFilter):
915
2443
  pass
916
2444
 
917
2445
  def makenet(self):
2446
+ """
2447
+ Create and configure a bidirectional LSTM neural network model.
2448
+
2449
+ This function builds a sequential neural network architecture using bidirectional LSTM layers
2450
+ followed by time-distributed dense layers. The model is compiled with Adam optimizer and MSE loss.
2451
+
2452
+ Parameters
2453
+ ----------
2454
+ self : object
2455
+ The instance containing the following attributes:
2456
+ - num_layers : int
2457
+ Number of LSTM layers in the model
2458
+ - num_units : int
2459
+ Number of units in each LSTM layer
2460
+ - dropout_rate : float
2461
+ Dropout rate for both dropout and recurrent dropout
2462
+ - window_size : int
2463
+ Size of the input window for time series data
2464
+
2465
+ Returns
2466
+ -------
2467
+ None
2468
+ This method modifies the instance in-place by setting the `model` attribute.
2469
+
2470
+ Notes
2471
+ -----
2472
+ The model architecture consists of:
2473
+ 1. Bidirectional LSTM layers with specified number of units and dropout rates
2474
+ 2. TimeDistributed Dense layers to map outputs back to window size
2475
+ 3. Compilation with Adam optimizer and MSE loss function
2476
+
2477
+ Examples
2478
+ --------
2479
+ >>> model_instance = MyModel()
2480
+ >>> model_instance.num_layers = 2
2481
+ >>> model_instance.num_units = 50
2482
+ >>> model_instance.dropout_rate = 0.2
2483
+ >>> model_instance.window_size = 10
2484
+ >>> model_instance.makenet()
2485
+ >>> print(model_instance.model.summary())
2486
+ """
918
2487
  self.model = Sequential()
919
2488
 
920
2489
  # each layer consists of an LSTM followed by a dense time distributed layer to get it back to the window size
@@ -936,7 +2505,53 @@ class LSTMDLFilter(DeepLearningFilter):
936
2505
 
937
2506
 
938
2507
  class HybridDLFilter(DeepLearningFilter):
939
- def __init__(self, invert=False, num_filters=10, kernel_size=5, num_units=16, *args, **kwargs):
2508
+ def __init__(
2509
+ self,
2510
+ invert: bool = False,
2511
+ num_filters: int = 10,
2512
+ kernel_size: int = 5,
2513
+ num_units: int = 16,
2514
+ *args,
2515
+ **kwargs,
2516
+ ) -> None:
2517
+ """
2518
+ Initialize the HybridDLFilter layer.
2519
+
2520
+ Parameters
2521
+ ----------
2522
+ invert : bool, optional
2523
+ If True, inverts the filter operation, by default False
2524
+ num_filters : int, optional
2525
+ Number of filters to use in the convolutional layer, by default 10
2526
+ kernel_size : int, optional
2527
+ Size of the convolutional kernel, by default 5
2528
+ num_units : int, optional
2529
+ Number of units in the dense layer, by default 16
2530
+ *args
2531
+ Variable length argument list
2532
+ **kwargs
2533
+ Arbitrary keyword arguments
2534
+
2535
+ Returns
2536
+ -------
2537
+ None
2538
+ This method does not return a value
2539
+
2540
+ Notes
2541
+ -----
2542
+ This method initializes the hybrid deep learning filter by setting up
2543
+ the convolutional and dense layer parameters. The infodict is populated
2544
+ with configuration information for tracking and debugging purposes.
2545
+
2546
+ Examples
2547
+ --------
2548
+ >>> layer = HybridDLFilter(
2549
+ ... invert=True,
2550
+ ... num_filters=20,
2551
+ ... kernel_size=3,
2552
+ ... num_units=32
2553
+ ... )
2554
+ """
940
2555
  self.invert = invert
941
2556
  self.num_filters = num_filters
942
2557
  self.kernel_size = kernel_size
@@ -949,19 +2564,94 @@ class HybridDLFilter(DeepLearningFilter):
949
2564
  super(HybridDLFilter, self).__init__(*args, **kwargs)
950
2565
 
951
2566
  def getname(self):
2567
+ """
2568
+ Generate and return the model name and path based on current configuration parameters.
2569
+
2570
+ This method constructs a descriptive model name string by joining various configuration
2571
+ parameters with specific prefixes and formatting conventions. The resulting model name
2572
+ is used to create a unique directory path for model storage.
2573
+
2574
+ Parameters
2575
+ ----------
2576
+ self : object
2577
+ The instance containing model configuration parameters. Expected attributes include:
2578
+ - `window_size` : int
2579
+ - `num_layers` : int
2580
+ - `num_filters` : int
2581
+ - `kernel_size` : int
2582
+ - `num_units` : int
2583
+ - `dropout_rate` : float
2584
+ - `num_epochs` : int
2585
+ - `excludethresh` : float
2586
+ - `corrthresh_rp` : float
2587
+ - `step` : int
2588
+ - `activation` : str
2589
+ - `invert` : bool
2590
+ - `excludebysubject` : bool
2591
+ - `modelroot` : str
2592
+
2593
+ Returns
2594
+ -------
2595
+ None
2596
+ This method does not return a value but modifies instance attributes:
2597
+ - `self.modelname`: The constructed model name string
2598
+ - `self.modelpath`: The full path to the model directory
2599
+
2600
+ Notes
2601
+ -----
2602
+ The model name is constructed using the following components:
2603
+ - "model_hybrid_tf2_" prefix
2604
+ - Window size with 3-digit zero-padded formatting
2605
+ - Number of layers with 2-digit zero-padded formatting
2606
+ - Number of filters with 2-digit zero-padded formatting
2607
+ - Kernel size with 2-digit zero-padded formatting
2608
+ - Number of units
2609
+ - Dropout rate (appears twice with different prefixes)
2610
+ - Number of epochs with 3-digit zero-padded formatting
2611
+ - Exclusion threshold
2612
+ - Correlation threshold
2613
+ - Step size
2614
+ - Activation function name
2615
+
2616
+ Additional suffixes are appended based on boolean flags:
2617
+ - "_invert" if `self.invert` is True
2618
+ - "_excludebysubject" if `self.excludebysubject` is True
2619
+
2620
+ Examples
2621
+ --------
2622
+ >>> model = MyModel()
2623
+ >>> model.window_size = 100
2624
+ >>> model.num_layers = 3
2625
+ >>> model.num_filters = 16
2626
+ >>> model.kernel_size = 5
2627
+ >>> model.num_units = 64
2628
+ >>> model.dropout_rate = 0.2
2629
+ >>> model.num_epochs = 100
2630
+ >>> model.excludethresh = 0.5
2631
+ >>> model.corrthresh_rp = 0.8
2632
+ >>> model.step = 1
2633
+ >>> model.activation = "relu"
2634
+ >>> model.invert = True
2635
+ >>> model.excludebysubject = False
2636
+ >>> model.getname()
2637
+ >>> print(model.modelname)
2638
+ 'model_hybrid_tf2_w100_l03_fn16_fl05_nu64_d0.2_rd0.2_e100_t0.5_ct0.8_s01_relu_invert'
2639
+ """
952
2640
  self.modelname = "_".join(
953
2641
  [
954
2642
  "model",
955
2643
  "hybrid",
956
- "w" + str(self.window_size),
957
- "l" + str(self.num_layers),
958
- "fn" + str(self.num_filters),
959
- "fl" + str(self.kernel_size),
2644
+ "tf2",
2645
+ "w" + str(self.window_size).zfill(3),
2646
+ "l" + str(self.num_layers).zfill(2),
2647
+ "fn" + str(self.num_filters).zfill(2),
2648
+ "fl" + str(self.kernel_size).zfill(2),
960
2649
  "nu" + str(self.num_units),
961
2650
  "d" + str(self.dropout_rate),
962
2651
  "rd" + str(self.dropout_rate),
963
- "e" + str(self.num_epochs),
2652
+ "e" + str(self.num_epochs).zfill(3),
964
2653
  "t" + str(self.excludethresh),
2654
+ "ct" + str(self.corrthresh_rp),
965
2655
  "s" + str(self.step),
966
2656
  self.activation,
967
2657
  ]
@@ -978,6 +2668,71 @@ class HybridDLFilter(DeepLearningFilter):
978
2668
  pass
979
2669
 
980
2670
  def makenet(self):
2671
+ """
2672
+ Build and compile a neural network model with configurable CNN and LSTM layers.
2673
+
2674
+ This function constructs a neural network model using Keras, with the architecture
2675
+ determined by the `invert` flag. If `invert` is True, the model starts with a
2676
+ Conv1D layer followed by LSTM layers; otherwise, it starts with LSTM layers
2677
+ followed by Conv1D layers. The model is compiled with the RMSprop optimizer
2678
+ and mean squared error loss.
2679
+
2680
+ Parameters
2681
+ ----------
2682
+ self : object
2683
+ The instance of the class containing the model configuration attributes.
2684
+
2685
+ Attributes Used
2686
+ ---------------
2687
+ self.invert : bool
2688
+ If True, the model begins with a Conv1D layer and ends with an LSTM layer.
2689
+ If False, the model begins with an LSTM layer and ends with a Conv1D layer.
2690
+ self.num_filters : int
2691
+ Number of filters in each Conv1D layer.
2692
+ self.kernel_size : int
2693
+ Size of the kernel in Conv1D layers.
2694
+ self.padding : str, default='same'
2695
+ Padding mode for Conv1D layers.
2696
+ self.window_size : int
2697
+ Length of the input sequence.
2698
+ self.inputsize : int
2699
+ Number of features in the input data.
2700
+ self.num_layers : int
2701
+ Total number of layers in the model.
2702
+ self.num_units : int
2703
+ Number of units in the LSTM layers.
2704
+ self.dropout_rate : float
2705
+ Dropout rate for regularization.
2706
+ self.activation : str or callable
2707
+ Activation function for Conv1D layers.
2708
+
2709
+ Returns
2710
+ -------
2711
+ None
2712
+ This method modifies the instance's `self.model` attribute in place.
2713
+
2714
+ Notes
2715
+ -----
2716
+ - The model uses `Sequential` from Keras.
2717
+ - Batch normalization and dropout are applied after each Conv1D layer (except the last).
2718
+ - The final layer is a Dense layer wrapped in `TimeDistributed` for sequence-to-sequence output.
2719
+ - The model is compiled using `RMSprop` optimizer and `mse` loss.
2720
+
2721
+ Examples
2722
+ --------
2723
+ >>> model_builder = MyModelClass()
2724
+ >>> model_builder.invert = True
2725
+ >>> model_builder.num_filters = 32
2726
+ >>> model_builder.kernel_size = 3
2727
+ >>> model_builder.window_size = 100
2728
+ >>> model_builder.inputsize = 1
2729
+ >>> model_builder.num_layers = 5
2730
+ >>> model_builder.num_units = 64
2731
+ >>> model_builder.dropout_rate = 0.2
2732
+ >>> model_builder.activation = 'relu'
2733
+ >>> model_builder.makenet()
2734
+ >>> model_builder.model.summary()
2735
+ """
981
2736
  self.model = Sequential()
982
2737
 
983
2738
  if self.invert:
@@ -1059,14 +2814,67 @@ class HybridDLFilter(DeepLearningFilter):
1059
2814
 
1060
2815
 
1061
2816
  def filtscale(
1062
- data,
1063
- scalefac=1.0,
1064
- reverse=False,
1065
- hybrid=False,
1066
- lognormalize=True,
1067
- epsilon=1e-10,
1068
- numorders=6,
1069
- ):
2817
+ data: NDArray,
2818
+ scalefac: float = 1.0,
2819
+ reverse: bool = False,
2820
+ hybrid: bool = False,
2821
+ lognormalize: bool = True,
2822
+ epsilon: float = 1e-10,
2823
+ numorders: int = 6,
2824
+ ) -> tuple[NDArray, float] | NDArray:
2825
+ """
2826
+ Apply or reverse a frequency-domain scaling and normalization to input data.
2827
+
2828
+ This function performs either forward or inverse transformation of the input
2829
+ data in the frequency domain, applying scaling, normalization, and optionally
2830
+ hybrid encoding. It supports both logarithmic and standard normalization
2831
+ modes.
2832
+
2833
+ Parameters
2834
+ ----------
2835
+ data : NDArray
2836
+ Input signal or transformed data (depending on `reverse` flag).
2837
+ scalefac : float, optional
2838
+ Scaling factor used for normalization. Default is 1.0.
2839
+ reverse : bool, optional
2840
+ If True, performs inverse transformation from frequency domain back
2841
+ to time domain. Default is False.
2842
+ hybrid : bool, optional
2843
+ If True, returns a hybrid representation combining original data
2844
+ and magnitude spectrum. Default is False.
2845
+ lognormalize : bool, optional
2846
+ If True, applies logarithmic normalization to the magnitude spectrum.
2847
+ Default is True.
2848
+ epsilon : float, optional
2849
+ Small constant added to avoid log(0). Default is 1e-10.
2850
+ numorders : int, optional
2851
+ Number of orders used for scaling in log normalization. Default is 6.
2852
+
2853
+ Returns
2854
+ -------
2855
+ tuple[NDArray, float] or NDArray
2856
+ - If `reverse=False`: A tuple of (transformed data, scale factor).
2857
+ The transformed data is a stacked array of magnitude and phase components
2858
+ (or original data in hybrid mode).
2859
+ - If `reverse=True`: Reconstructed time-domain signal.
2860
+
2861
+ Notes
2862
+ -----
2863
+ - Forward mode applies FFT, normalizes the magnitude, and stacks magnitude
2864
+ and phase.
2865
+ - In hybrid mode, the output includes the original time-domain signal
2866
+ instead of the phase component.
2867
+ - In reverse mode, the phase and magnitude components are used to reconstruct
2868
+ the original signal using inverse FFT.
2869
+
2870
+ Examples
2871
+ --------
2872
+ >>> import numpy as np
2873
+ >>> from scipy import fftpack
2874
+ >>> x = np.random.randn(1024)
2875
+ >>> scaled_data, scale = filtscale(x)
2876
+ >>> reconstructed = filtscale(scaled_data, scale, reverse=True)
2877
+ """
1070
2878
  if not reverse:
1071
2879
  specvals = fftpack.fft(data)
1072
2880
  if lognormalize:
@@ -1096,67 +2904,302 @@ def filtscale(
1096
2904
  return fftpack.ifft(specvals).real
1097
2905
 
1098
2906
 
1099
- def tobadpts(name):
2907
+ def tobadpts(name: str) -> str:
2908
+ """
2909
+ Convert a filename to its corresponding bad points filename.
2910
+
2911
+ Replaces the '.txt' extension with '_badpts.txt' to create a standardized
2912
+ bad points filename pattern.
2913
+
2914
+ Parameters
2915
+ ----------
2916
+ name : str
2917
+ Input filename, typically ending with '.txt' extension.
2918
+
2919
+ Returns
2920
+ -------
2921
+ str
2922
+ Filename with '.txt' replaced by '_badpts.txt' extension.
2923
+
2924
+ Notes
2925
+ -----
2926
+ This function assumes the input filename ends with '.txt' extension.
2927
+ If the input does not contain '.txt', the function will append '_badpts.txt'
2928
+ to the end of the string.
2929
+
2930
+ Examples
2931
+ --------
2932
+ >>> tobadpts("data.txt")
2933
+ 'data_badpts.txt'
2934
+
2935
+ >>> tobadpts("results.txt")
2936
+ 'results_badpts.txt'
2937
+
2938
+ >>> tobadpts("config")
2939
+ 'config_badpts.txt'
2940
+ """
1100
2941
  return name.replace(".txt", "_badpts.txt")
1101
2942
 
1102
2943
 
1103
- def targettoinput(name, targetfrag="xyz", inputfrag="abc"):
2944
+ def targettoinput(name: str, targetfrag: str = "xyz", inputfrag: str = "abc") -> str:
2945
+ """
2946
+ Replace occurrences of a target fragment with an input fragment in a string.
2947
+
2948
+ Parameters
2949
+ ----------
2950
+ name : str
2951
+ The input string to process.
2952
+ targetfrag : str, default='xyz'
2953
+ The fragment to search for and replace. Defaults to 'xyz'.
2954
+ inputfrag : str, default='abc'
2955
+ The fragment to replace targetfrag with. Defaults to 'abc'.
2956
+
2957
+ Returns
2958
+ -------
2959
+ str
2960
+ The modified string with targetfrag replaced by inputfrag.
2961
+
2962
+ Notes
2963
+ -----
2964
+ This function uses Python's built-in string replace method, which replaces
2965
+ all occurrences of targetfrag with inputfrag in the input string.
2966
+
2967
+ Examples
2968
+ --------
2969
+ >>> targettoinput("hello xyz world")
2970
+ 'hello abc world'
2971
+
2972
+ >>> targettoinput("xyzxyzxyz", "xyz", "123")
2973
+ '123123123'
2974
+
2975
+ >>> targettoinput("abcdef", "xyz", "123")
2976
+ 'abcdef'
2977
+ """
1104
2978
  LGR.debug(f"replacing {targetfrag} with {inputfrag}")
1105
2979
  return name.replace(targetfrag, inputfrag)
1106
2980
 
1107
2981
 
1108
- def getmatchedfiles(searchstring, usebadpts=False, targetfrag="xyz", inputfrag="abc"):
1109
- # list all of the target files
2982
+ def getmatchedtcs(
2983
+ searchstring: str,
2984
+ usebadpts: bool = False,
2985
+ targetfrag: str = "xyz",
2986
+ inputfrag: str = "abc",
2987
+ debug: bool = False,
2988
+ ) -> tuple[list[str], int]:
2989
+ """
2990
+ Find and validate timecourse files matching a search pattern, and determine the length of the timecourses.
2991
+
2992
+ This function searches for files matching the given `searchstring`, checks for the existence of
2993
+ corresponding info files to ensure completeness, and reads the first matched file to determine
2994
+ the length of the timecourses. It is intended for use with BIDS-compatible timecourse files.
2995
+
2996
+ Parameters
2997
+ ----------
2998
+ searchstring : str
2999
+ A glob pattern to match target files. Typically includes a path and file name pattern.
3000
+ usebadpts : bool, optional
3001
+ Flag indicating whether to use bad points in processing. Default is False.
3002
+ targetfrag : str, optional
3003
+ Fragment identifier for target files. Default is "xyz".
3004
+ inputfrag : str, optional
3005
+ Fragment identifier for input files. Default is "abc".
3006
+ debug : bool, optional
3007
+ If True, print debug information including matched files and processing steps.
3008
+ Default is False.
3009
+
3010
+ Returns
3011
+ -------
3012
+ tuple[list[str], int]
3013
+ A tuple containing:
3014
+ - List of matched and validated file paths.
3015
+ - Length of the timecourses (number of timepoints) in the first matched file.
3016
+
3017
+ Notes
3018
+ -----
3019
+ - The function expects files to have a corresponding `_info` file for validation.
3020
+ - Timecourse data is read from the first matched file using `tide_io.readbidstsv`.
3021
+ - The function currently only reads the first matched file to determine `tclen`, assuming all
3022
+ matched files have the same timecourse length.
3023
+
3024
+ Examples
3025
+ --------
3026
+ >>> matched_files, length = getmatchedtcs("sub-*/func/*cardiacfromfmri_25.0Hz*")
3027
+ >>> print(f"Found {len(matched_files)} files with {length} timepoints each.")
3028
+ """
3029
+ # list all the target files
1110
3030
  fromfile = sorted(glob.glob(searchstring))
1111
- LGR.debug(f"searchstring: {searchstring} -> {fromfile}")
3031
+ if debug:
3032
+ print(f"searchstring: {searchstring} -> {fromfile}")
1112
3033
 
1113
- # make sure all files exist
3034
+ # make sure all timecourses exist
3035
+ # we need cardiacfromfmri_25.0Hz as x, normpleth as y, and perhaps badpts
1114
3036
  matchedfilelist = []
1115
3037
  for targetname in fromfile:
1116
- if os.path.isfile(targettoinput(targetname, targetfrag=targetfrag, inputfrag=inputfrag)):
1117
- if usebadpts:
1118
- if os.path.isfile(
1119
- tobadpts(targetname.replace("alignedpleth", "pleth"))
1120
- ) and os.path.isfile(
1121
- tobadpts(
1122
- targettoinput(
1123
- targetname,
1124
- targetfrag=targetfrag,
1125
- inputfrag=inputfrag,
1126
- )
1127
- )
1128
- ):
1129
- matchedfilelist.append(targetname)
1130
- LGR.debug(matchedfilelist[-1])
1131
- else:
1132
- matchedfilelist.append(targetname)
1133
- LGR.debug(matchedfilelist[-1])
1134
- if usebadpts:
1135
- LGR.info(f"{len(matchedfilelist)} runs pass all 4 files present check")
1136
- else:
1137
- LGR.info(f"{len(matchedfilelist)} runs pass both files present check")
3038
+ infofile = targetname.replace("_desc-stdrescardfromfmri_timeseries", "_info")
3039
+ if os.path.isfile(infofile):
3040
+ matchedfilelist.append(targetname)
3041
+ print(f"{targetname} is complete")
3042
+ LGR.debug(matchedfilelist[-1])
3043
+ else:
3044
+ print(f"{targetname} is incomplete")
3045
+ print(f"found {len(matchedfilelist)} matched files")
1138
3046
 
1139
3047
  # find out how long the files are
1140
- tempy = np.loadtxt(matchedfilelist[0])
1141
- tempx = np.loadtxt(
1142
- targettoinput(matchedfilelist[0], targetfrag=targetfrag, inputfrag=inputfrag)
3048
+ (
3049
+ samplerate,
3050
+ starttime,
3051
+ columns,
3052
+ inputarray,
3053
+ compression,
3054
+ columnsource,
3055
+ extrainfo,
3056
+ ) = tide_io.readbidstsv(
3057
+ matchedfilelist[0],
3058
+ colspec="cardiacfromfmri_25.0Hz,normpleth",
1143
3059
  )
1144
- tclen = np.min([tempx.shape[0], tempy.shape[0]])
3060
+ print(f"{inputarray.shape=}")
3061
+ tclen = inputarray.shape[1]
1145
3062
  LGR.info(f"tclen set to {tclen}")
1146
3063
  return matchedfilelist, tclen
1147
3064
 
1148
3065
 
1149
3066
  def readindata(
1150
- matchedfilelist,
1151
- tclen,
1152
- targetfrag="xyz",
1153
- inputfrag="abc",
1154
- usebadpts=False,
1155
- startskip=0,
1156
- endskip=0,
1157
- readlim=None,
1158
- readskip=None,
1159
- ):
3067
+ matchedfilelist: list[str],
3068
+ tclen: int,
3069
+ targetfrag: str = "xyz",
3070
+ inputfrag: str = "abc",
3071
+ usebadpts: bool = False,
3072
+ startskip: int = 0,
3073
+ endskip: int = 0,
3074
+ corrthresh_rp: float = 0.5,
3075
+ readlim: int | None = None,
3076
+ readskip: int | None = None,
3077
+ debug: bool = False,
3078
+ ) -> tuple[NDArray, NDArray, list[str]] | tuple[NDArray, NDArray, list[str], NDArray]:
3079
+ """
3080
+ Read and process time-series data from a list of matched files.
3081
+
3082
+ This function reads cardiac and plethysmographic data from a set of files, applies
3083
+ filtering based on data quality metrics (e.g., correlation thresholds, NaN values,
3084
+ data length, and standard deviation), and returns processed arrays for training.
3085
+
3086
+ Parameters
3087
+ ----------
3088
+ matchedfilelist : list of str
3089
+ List of file paths to be processed. Each file should contain time-series data
3090
+ in a format compatible with `tide_io.readbidstsv`.
3091
+ tclen : int
3092
+ The length of the time series to be read from each file.
3093
+ targetfrag : str, optional
3094
+ Fragment identifier used for mapping filenames (default is "xyz").
3095
+ inputfrag : str, optional
3096
+ Fragment identifier used for mapping filenames (default is "abc").
3097
+ usebadpts : bool, optional
3098
+ If True, include bad point data in the output (default is False).
3099
+ startskip : int, optional
3100
+ Number of samples to skip at the beginning of each time series (default is 0).
3101
+ endskip : int, optional
3102
+ Number of samples to skip at the end of each time series (default is 0).
3103
+ corrthresh_rp : float, optional
3104
+ Threshold for correlation between raw and plethysmographic signals.
3105
+ Files with correlations below this value are excluded (default is 0.5).
3106
+ readlim : int, optional
3107
+ Maximum number of files to read. If None, all files are read (default is None).
3108
+ readskip : int, optional
3109
+ Number of files to skip at the beginning of the list. If None, no files are skipped (default is None).
3110
+ debug : bool, optional
3111
+ If True, print debug information during processing (default is False).
3112
+
3113
+ Returns
3114
+ -------
3115
+ tuple of (NDArray, NDArray, list[str]) or (NDArray, NDArray, list[str], NDArray)
3116
+ - `x1[startskip:-endskip, :count]`: Array of x-axis time series data.
3117
+ - `y1[startskip:-endskip, :count]`: Array of y-axis time series data.
3118
+ - `names[:count]`: List of file names that passed quality checks.
3119
+ - `bad1[startskip:-endskip, :count]`: Optional array of bad point data if `usebadpts` is True.
3120
+
3121
+ Notes
3122
+ -----
3123
+ - Files are filtered based on:
3124
+ - Correlation threshold (`corrthresh_rp`)
3125
+ - Presence of NaN values
3126
+ - Data length (must be at least `tclen`)
3127
+ - Standard deviation of data (must be between 0.5 and 20.0)
3128
+ - Excluded files are logged with reasons.
3129
+ - If `usebadpts` is True, bad point data is included in the returned tuple.
3130
+
3131
+ Examples
3132
+ --------
3133
+ >>> x, y, names = readindata(
3134
+ ... matchedfilelist=["file1.tsv", "file2.tsv"],
3135
+ ... tclen=1000,
3136
+ ... corrthresh_rp=0.6,
3137
+ ... readlim=10
3138
+ ... )
3139
+ >>> print(f"Loaded {len(names)} files")
3140
+ """
3141
+ """
3142
+ Read and process time-series data from a list of matched files.
3143
+
3144
+ This function reads cardiac and plethysmographic data from a set of files, applies
3145
+ filtering based on data quality metrics (e.g., correlation thresholds, NaN values,
3146
+ data length, and standard deviation), and returns processed arrays for training.
3147
+
3148
+ Parameters
3149
+ ----------
3150
+ matchedfilelist : list of str
3151
+ List of file paths to be processed. Each file should contain time-series data
3152
+ in a format compatible with `tide_io.readbidstsv`.
3153
+ tclen : int
3154
+ The length of the time series to be read from each file.
3155
+ targetfrag : str, optional
3156
+ Fragment identifier used for mapping filenames (default is "xyz").
3157
+ inputfrag : str, optional
3158
+ Fragment identifier used for mapping filenames (default is "abc").
3159
+ usebadpts : bool, optional
3160
+ If True, include bad point data in the output (default is False).
3161
+ startskip : int, optional
3162
+ Number of samples to skip at the beginning of each time series (default is 0).
3163
+ endskip : int, optional
3164
+ Number of samples to skip at the end of each time series (default is 0).
3165
+ corrthresh_rp : float, optional
3166
+ Threshold for correlation between raw and plethysmographic signals.
3167
+ Files with correlations below this value are excluded (default is 0.5).
3168
+ readlim : int, optional
3169
+ Maximum number of files to read. If None, all files are read (default is None).
3170
+ readskip : int, optional
3171
+ Number of files to skip at the beginning of the list. If None, no files are skipped (default is None).
3172
+ debug : bool, optional
3173
+ If True, print debug information during processing (default is False).
3174
+
3175
+ Returns
3176
+ -------
3177
+ tuple of (NDArray, NDArray, list[str]) or (NDArray, NDArray, list[str], NDArray)
3178
+ - `x1[startskip:-endskip, :count]`: Array of x-axis time series data.
3179
+ - `y1[startskip:-endskip, :count]`: Array of y-axis time series data.
3180
+ - `names[:count]`: List of file names that passed quality checks.
3181
+ - `bad1[startskip:-endskip, :count]`: Optional array of bad point data if `usebadpts` is True.
3182
+
3183
+ Notes
3184
+ -----
3185
+ - Files are filtered based on:
3186
+ - Correlation threshold (`corrthresh_rp`)
3187
+ - Presence of NaN values
3188
+ - Data length (must be at least `tclen`)
3189
+ - Standard deviation of data (must be between 0.5 and 20.0)
3190
+ - Excluded files are logged with reasons.
3191
+ - If `usebadpts` is True, bad point data is included in the returned tuple.
3192
+
3193
+ Examples
3194
+ --------
3195
+ >>> x, y, names = readindata(
3196
+ ... matchedfilelist=["file1.tsv", "file2.tsv"],
3197
+ ... tclen=1000,
3198
+ ... corrthresh_rp=0.6,
3199
+ ... readlim=10
3200
+ ... )
3201
+ >>> print(f"Loaded {len(names)} files")
3202
+ """
1160
3203
  LGR.info(
1161
3204
  "readindata called with usebadpts, startskip, endskip, readlim, readskip, targetfrag, inputfrag = "
1162
3205
  f"{usebadpts} {startskip} {endskip} {readlim} {readskip} {targetfrag} {inputfrag}"
@@ -1177,20 +3220,37 @@ def readindata(
1177
3220
  # now read the data in
1178
3221
  count = 0
1179
3222
  LGR.info("checking data")
3223
+ lowcorrfiles = []
1180
3224
  nanfiles = []
1181
3225
  shortfiles = []
1182
3226
  strangemagfiles = []
1183
3227
  for i in range(readskip, readskip + s):
3228
+ lowcorrfound = False
1184
3229
  nanfound = False
1185
3230
  LGR.info(f"processing {matchedfilelist[i]}")
1186
- tempy = np.loadtxt(matchedfilelist[i])
1187
- tempx = np.loadtxt(
1188
- targettoinput(
1189
- matchedfilelist[i],
1190
- targetfrag=targetfrag,
1191
- inputfrag=inputfrag,
1192
- )
3231
+
3232
+ # read the info dict first
3233
+ infodict = tide_io.readdictfromjson(
3234
+ matchedfilelist[i].replace("_desc-stdrescardfromfmri_timeseries", "_info")
1193
3235
  )
3236
+ if infodict["corrcoeff_raw2pleth"] < corrthresh_rp:
3237
+ lowcorrfound = True
3238
+ lowcorrfiles.append(matchedfilelist[i])
3239
+ (
3240
+ samplerate,
3241
+ starttime,
3242
+ columns,
3243
+ inputarray,
3244
+ compression,
3245
+ columnsource,
3246
+ extrainfo,
3247
+ ) = tide_io.readbidstsv(
3248
+ matchedfilelist[i],
3249
+ colspec="cardiacfromfmri_25.0Hz,normpleth",
3250
+ )
3251
+ tempy = inputarray[1, :]
3252
+ tempx = inputarray[0, :]
3253
+
1194
3254
  if np.any(np.isnan(tempy)):
1195
3255
  LGR.info(f"NaN found in file {matchedfilelist[i]} - discarding")
1196
3256
  nanfound = True
@@ -1204,23 +3264,23 @@ def readindata(
1204
3264
  nanfiles.append(nan_fname)
1205
3265
  strangefound = False
1206
3266
  if not (0.5 < np.std(tempx) < 20.0):
1207
- strange_fname = targettoinput(
1208
- matchedfilelist[i], targetfrag=targetfrag, inputfrag=inputfrag
3267
+ strange_fname = matchedfilelist[i]
3268
+ LGR.info(
3269
+ f"file {strange_fname} has an extreme cardiacfromfmri standard deviation - discarding"
1209
3270
  )
1210
- LGR.info(f"file {strange_fname} has an extreme standard deviation - discarding")
1211
3271
  strangefound = True
1212
3272
  strangemagfiles.append(strange_fname)
1213
3273
  if not (0.5 < np.std(tempy) < 20.0):
1214
- LGR.info(f"file {matchedfilelist[i]} has an extreme standard deviation - discarding")
3274
+ LGR.info(
3275
+ f"file {matchedfilelist[i]} has an extreme normpleth standard deviation - discarding"
3276
+ )
1215
3277
  strangefound = True
1216
3278
  strangemagfiles.append(matchedfilelist[i])
1217
3279
  shortfound = False
1218
3280
  ntempx = tempx.shape[0]
1219
3281
  ntempy = tempy.shape[0]
1220
3282
  if ntempx < tclen:
1221
- short_fname = targettoinput(
1222
- matchedfilelist[i], targetfrag=targetfrag, inputfrag=inputfrag
1223
- )
3283
+ short_fname = matchedfilelist[i]
1224
3284
  LGR.info(f"file {short_fname} is short - discarding")
1225
3285
  shortfound = True
1226
3286
  shortfiles.append(short_fname)
@@ -1234,26 +3294,31 @@ def readindata(
1234
3294
  and (not nanfound)
1235
3295
  and (not shortfound)
1236
3296
  and (not strangefound)
3297
+ and (not lowcorrfound)
1237
3298
  ):
1238
3299
  x1[:tclen, count] = tempx[:tclen]
1239
3300
  y1[:tclen, count] = tempy[:tclen]
1240
3301
  names.append(matchedfilelist[i])
3302
+ if debug:
3303
+ print(f"{matchedfilelist[i]} included:")
1241
3304
  if usebadpts:
1242
- tempbad1 = np.loadtxt(
1243
- tobadpts(matchedfilelist[i].replace("alignedpleth", "pleth"))
1244
- )
1245
- tempbad2 = np.loadtxt(
1246
- tobadpts(
1247
- targettoinput(
1248
- matchedfilelist[i],
1249
- targetfrag=targetfrag,
1250
- inputfrag=inputfrag,
1251
- )
1252
- )
1253
- )
1254
- bad1[:tclen, count] = 1.0 - (1.0 - tempbad1[:tclen]) * (1.0 - tempbad2[:tclen])
3305
+ bad1[:tclen, count] = inputarray[2, :]
1255
3306
  count += 1
3307
+ else:
3308
+ print(f"{matchedfilelist[i]} excluded:")
3309
+ if ntempx < tclen:
3310
+ print("\tx data too short")
3311
+ if ntempy < tclen:
3312
+ print("\ty data too short")
3313
+ print(f"\t{nanfound=}")
3314
+ print(f"\t{shortfound=}")
3315
+ print(f"\t{strangefound=}")
3316
+ print(f"\t{lowcorrfound=}")
1256
3317
  LGR.info(f"{count} runs pass file length check")
3318
+ if len(lowcorrfiles) > 0:
3319
+ LGR.info("files with low raw/pleth correlations:")
3320
+ for thefile in lowcorrfiles:
3321
+ LGR.info(f"\t{thefile}")
1257
3322
  if len(nanfiles) > 0:
1258
3323
  LGR.info("files with NaNs:")
1259
3324
  for thefile in nanfiles:
@@ -1267,6 +3332,7 @@ def readindata(
1267
3332
  for thefile in strangemagfiles:
1268
3333
  LGR.info(f"\t{thefile}")
1269
3334
 
3335
+ print(f"training set contains {count} runs of length {tclen}")
1270
3336
  if usebadpts:
1271
3337
  return (
1272
3338
  x1[startskip:-endskip, :count],
@@ -1283,64 +3349,136 @@ def readindata(
1283
3349
 
1284
3350
 
1285
3351
  def prep(
1286
- window_size,
1287
- step=1,
1288
- excludethresh=4.0,
1289
- usebadpts=False,
1290
- startskip=200,
1291
- endskip=200,
1292
- excludebysubject=True,
1293
- thesuffix="sliceres",
1294
- thedatadir="/data1/frederic/test/output",
1295
- inputfrag="abc",
1296
- targetfrag="xyz",
1297
- dofft=False,
1298
- readlim=None,
1299
- readskip=None,
1300
- countlim=None,
3352
+ window_size: int,
3353
+ step: int = 1,
3354
+ excludethresh: float = 4.0,
3355
+ usebadpts: bool = False,
3356
+ startskip: int = 200,
3357
+ endskip: int = 200,
3358
+ excludebysubject: bool = True,
3359
+ thesuffix: str = "sliceres",
3360
+ thedatadir: str = "/data/frederic/physioconn/output_2025",
3361
+ inputfrag: str = "abc",
3362
+ targetfrag: str = "xyz",
3363
+ corrthresh_rp: float = 0.5,
3364
+ dofft: bool = False,
3365
+ readlim: int | None = None,
3366
+ readskip: int | None = None,
3367
+ countlim: int | None = None,
3368
+ debug: bool = False,
3369
+ ) -> (
3370
+ tuple[NDArray, NDArray, NDArray, NDArray, int, int, int]
3371
+ | tuple[NDArray, NDArray, NDArray, NDArray, int, int, int, NDArray, NDArray]
1301
3372
  ):
1302
3373
  """
1303
- prep - reads in training and validation data for 1D filter
3374
+ Prepare time-series data for training and validation by reading, normalizing,
3375
+ windowing, and splitting into batches.
3376
+
3377
+ This function reads time-series data from JSON files, normalizes the data,
3378
+ applies windowing to create input-output pairs, and splits the data into
3379
+ training and validation sets based on subject-wise or window-wise exclusion
3380
+ criteria.
1304
3381
 
1305
3382
  Parameters
1306
3383
  ----------
1307
- window_size
1308
- step
1309
- excludethresh
1310
- excludebysubject
1311
- usebadpts
1312
- startskip
1313
- endskip
1314
- thesuffix
1315
- thedatadir
1316
- inputfrag
1317
- targetfrag
1318
- dofft
1319
- readlim
1320
- readskip
1321
- countlim
3384
+ window_size : int
3385
+ Size of the sliding window used to create input-output pairs.
3386
+ step : int, optional
3387
+ Step size for sliding window (default is 1).
3388
+ excludethresh : float, optional
3389
+ Threshold for excluding windows or subjects based on maximum absolute
3390
+ value of input data (default is 4.0).
3391
+ usebadpts : bool, optional
3392
+ Whether to include bad points in the data (default is False).
3393
+ startskip : int, optional
3394
+ Number of time points to skip at the beginning of each time series
3395
+ (default is 200).
3396
+ endskip : int, optional
3397
+ Number of time points to skip at the end of each time series
3398
+ (default is 200).
3399
+ excludebysubject : bool, optional
3400
+ If True, exclude entire subjects based on maximum absolute value;
3401
+ otherwise, exclude individual windows (default is True).
3402
+ thesuffix : str, optional
3403
+ Suffix used to identify files (default is "sliceres").
3404
+ thedatadir : str, optional
3405
+ Directory where the data files are located (default is
3406
+ "/data/frederic/physioconn/output_2025").
3407
+ inputfrag : str, optional
3408
+ Fragment identifier for input data (default is "abc").
3409
+ targetfrag : str, optional
3410
+ Fragment identifier for target data (default is "xyz").
3411
+ corrthresh_rp : float, optional
3412
+ Correlation threshold for matching time series (default is 0.5).
3413
+ dofft : bool, optional
3414
+ Whether to perform FFT on the data (default is False).
3415
+ readlim : int or None, optional
3416
+ Limit on number of time points to read (default is None).
3417
+ readskip : int or None, optional
3418
+ Number of time points to skip when reading data (default is None).
3419
+ countlim : int or None, optional
3420
+ Limit on number of subjects to process (default is None).
3421
+ debug : bool, optional
3422
+ Whether to enable debug logging (default is False).
1322
3423
 
1323
3424
  Returns
1324
3425
  -------
1325
- train_x, train_y, val_x, val_y, N_subjs, tclen - startskip, batchsize
1326
-
3426
+ tuple of (NDArray, NDArray, NDArray, NDArray, int, int, int)
3427
+ If `dofft` is False:
3428
+ - train_x : ndarray of shape (n_train, window_size, 1)
3429
+ - train_y : ndarray of shape (n_train, window_size, 1)
3430
+ - val_x : ndarray of shape (n_val, window_size, 1)
3431
+ - val_y : ndarray of shape (n_val, window_size, 1)
3432
+ - N_subjs : int
3433
+ - tclen : int
3434
+ - batchsize : int
3435
+
3436
+ tuple of (NDArray, NDArray, NDArray, NDArray, int, int, int,
3437
+ NDArray, NDArray)
3438
+ If `dofft` is True:
3439
+ - train_x : ndarray of shape (n_train, window_size, 2)
3440
+ - train_y : ndarray of shape (n_train, window_size, 2)
3441
+ - val_x : ndarray of shape (n_val, window_size, 2)
3442
+ - val_y : ndarray of shape (n_val, window_size, 2)
3443
+ - N_subjs : int
3444
+ - tclen : int
3445
+ - batchsize : int
3446
+ - Xscale_fourier : ndarray of shape (N_subjs, windowspersubject)
3447
+ - Yscale_fourier : ndarray of shape (N_subjs, windowspersubject)
3448
+
3449
+ Notes
3450
+ -----
3451
+ - Data normalization is performed using median absolute deviation (MAD).
3452
+ - Windows are created based on sliding window approach.
3453
+ - Training and validation sets are split based on subject-wise partitioning.
3454
+ - If `usebadpts` is True, bad points are included in the returned data.
3455
+ - If `dofft` is True, data is transformed using a filtering scale function.
3456
+
3457
+ Examples
3458
+ --------
3459
+ >>> train_x, train_y, val_x, val_y, N_subjs, tclen, batchsize = prep(
3460
+ ... window_size=100, step=10, excludethresh=3.0, dofft=False
3461
+ ... )
1327
3462
  """
1328
-
1329
- searchstring = os.path.join(thedatadir, "*_" + targetfrag + "_" + thesuffix + ".txt")
3463
+ searchstring = os.path.join(thedatadir, "*", "*_desc-stdrescardfromfmri_timeseries.json")
1330
3464
 
1331
3465
  # find matched files
1332
- matchedfilelist, tclen = getmatchedfiles(
3466
+ matchedfilelist, tclen = getmatchedtcs(
1333
3467
  searchstring,
1334
3468
  usebadpts=usebadpts,
1335
3469
  targetfrag=targetfrag,
1336
3470
  inputfrag=inputfrag,
3471
+ debug=debug,
1337
3472
  )
3473
+ # print("matchedfilelist", matchedfilelist)
3474
+ print("tclen", tclen)
1338
3475
 
1339
3476
  # read in the data from the matched files
1340
3477
  if usebadpts:
1341
3478
  x, y, names, bad = readindata(
1342
3479
  matchedfilelist,
1343
3480
  tclen,
3481
+ corrthresh_rp=corrthresh_rp,
1344
3482
  targetfrag=targetfrag,
1345
3483
  inputfrag=inputfrag,
1346
3484
  usebadpts=True,
@@ -1353,6 +3491,7 @@ def prep(
1353
3491
  x, y, names = readindata(
1354
3492
  matchedfilelist,
1355
3493
  tclen,
3494
+ corrthresh_rp=corrthresh_rp,
1356
3495
  targetfrag=targetfrag,
1357
3496
  inputfrag=inputfrag,
1358
3497
  startskip=startskip,