rapidtide 2.9.6__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.
- cloud/gmscalc-HCPYA +1 -1
- cloud/mount-and-run +2 -0
- cloud/rapidtide-HCPYA +3 -3
- rapidtide/Colortables.py +538 -38
- rapidtide/OrthoImageItem.py +1094 -51
- rapidtide/RapidtideDataset.py +1709 -114
- rapidtide/__init__.py +0 -8
- rapidtide/_version.py +4 -4
- rapidtide/calccoherence.py +242 -97
- rapidtide/calcnullsimfunc.py +240 -140
- rapidtide/calcsimfunc.py +314 -129
- rapidtide/correlate.py +1211 -389
- rapidtide/data/examples/src/testLD +56 -0
- rapidtide/data/examples/src/test_findmaxlag.py +2 -2
- rapidtide/data/examples/src/test_mlregressallt.py +32 -17
- rapidtide/data/examples/src/testalign +1 -1
- rapidtide/data/examples/src/testatlasaverage +35 -7
- rapidtide/data/examples/src/testboth +21 -0
- rapidtide/data/examples/src/testcifti +11 -0
- rapidtide/data/examples/src/testdelayvar +13 -0
- rapidtide/data/examples/src/testdlfilt +25 -0
- rapidtide/data/examples/src/testfft +35 -0
- rapidtide/data/examples/src/testfileorfloat +37 -0
- rapidtide/data/examples/src/testfmri +92 -42
- rapidtide/data/examples/src/testfuncs +3 -3
- rapidtide/data/examples/src/testglmfilt +8 -6
- rapidtide/data/examples/src/testhappy +84 -51
- rapidtide/data/examples/src/testinitdelay +19 -0
- rapidtide/data/examples/src/testmodels +33 -0
- rapidtide/data/examples/src/testnewrefine +26 -0
- rapidtide/data/examples/src/testnoiseamp +2 -2
- rapidtide/data/examples/src/testppgproc +17 -0
- rapidtide/data/examples/src/testrefineonly +22 -0
- rapidtide/data/examples/src/testretro +26 -13
- rapidtide/data/examples/src/testretrolagtcs +16 -0
- rapidtide/data/examples/src/testrolloff +11 -0
- rapidtide/data/examples/src/testsimdata +45 -28
- rapidtide/data/models/model_cnn_pytorch/loss.png +0 -0
- rapidtide/data/models/model_cnn_pytorch/loss.txt +1 -0
- rapidtide/data/models/model_cnn_pytorch/model.pth +0 -0
- rapidtide/data/models/model_cnn_pytorch/model_meta.json +68 -0
- rapidtide/data/models/model_cnn_pytorch_fulldata/loss.png +0 -0
- rapidtide/data/models/model_cnn_pytorch_fulldata/loss.txt +1 -0
- rapidtide/data/models/model_cnn_pytorch_fulldata/model.pth +0 -0
- rapidtide/data/models/model_cnn_pytorch_fulldata/model_meta.json +80 -0
- rapidtide/data/models/model_cnnbp_pytorch_fullldata/loss.png +0 -0
- rapidtide/data/models/model_cnnbp_pytorch_fullldata/loss.txt +1 -0
- rapidtide/data/models/model_cnnbp_pytorch_fullldata/model.pth +0 -0
- rapidtide/data/models/model_cnnbp_pytorch_fullldata/model_meta.json +138 -0
- rapidtide/data/models/model_cnnfft_pytorch_fulldata/loss.png +0 -0
- rapidtide/data/models/model_cnnfft_pytorch_fulldata/loss.txt +1 -0
- rapidtide/data/models/model_cnnfft_pytorch_fulldata/model.pth +0 -0
- rapidtide/data/models/model_cnnfft_pytorch_fulldata/model_meta.json +128 -0
- rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/loss.png +0 -0
- rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/loss.txt +1 -0
- rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/model.pth +0 -0
- rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/model_meta.json +49 -0
- rapidtide/data/models/model_revised_tf2/model.keras +0 -0
- rapidtide/data/models/{model_serdar → model_revised_tf2}/model_meta.json +1 -1
- rapidtide/data/models/model_serdar2_tf2/model.keras +0 -0
- rapidtide/data/models/{model_serdar2 → model_serdar2_tf2}/model_meta.json +1 -1
- rapidtide/data/models/model_serdar_tf2/model.keras +0 -0
- rapidtide/data/models/{model_revised → model_serdar_tf2}/model_meta.json +1 -1
- rapidtide/data/reference/HCP1200v2_MTT_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_binmask_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_csf_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_gray_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_graylaghist.json +7 -0
- rapidtide/data/reference/HCP1200v2_graylaghist.tsv.gz +0 -0
- rapidtide/data/reference/HCP1200v2_laghist.json +7 -0
- rapidtide/data/reference/HCP1200v2_laghist.tsv.gz +0 -0
- rapidtide/data/reference/HCP1200v2_mask_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_maxcorr_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_maxtime_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_maxwidth_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_negmask_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_timepercentile_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_white_2mm.nii.gz +0 -0
- rapidtide/data/reference/HCP1200v2_whitelaghist.json +7 -0
- rapidtide/data/reference/HCP1200v2_whitelaghist.tsv.gz +0 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2.xml +131 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2_regions.txt +60 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2_space-MNI152NLin6Asym_2mm.nii.gz +0 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm.nii.gz +0 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm_mask.nii.gz +0 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin6Asym_2mm_mask.nii.gz +0 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL2_space-MNI152NLin6Asym_2mm_mask.nii.gz +0 -0
- rapidtide/data/reference/MNI152_T1_1mm_Brain_FAST_seg.nii.gz +0 -0
- rapidtide/data/reference/MNI152_T1_1mm_Brain_Mask.nii.gz +0 -0
- rapidtide/data/reference/MNI152_T1_2mm_Brain_FAST_seg.nii.gz +0 -0
- rapidtide/data/reference/MNI152_T1_2mm_Brain_Mask.nii.gz +0 -0
- rapidtide/decorators.py +91 -0
- rapidtide/dlfilter.py +2553 -414
- rapidtide/dlfiltertorch.py +5201 -0
- rapidtide/externaltools.py +328 -13
- rapidtide/fMRIData_class.py +108 -92
- rapidtide/ffttools.py +168 -0
- rapidtide/filter.py +2704 -1462
- rapidtide/fit.py +2361 -579
- rapidtide/genericmultiproc.py +197 -0
- rapidtide/happy_supportfuncs.py +3255 -548
- rapidtide/helper_classes.py +587 -1116
- rapidtide/io.py +2569 -468
- rapidtide/linfitfiltpass.py +784 -0
- rapidtide/makelaggedtcs.py +267 -97
- rapidtide/maskutil.py +555 -25
- rapidtide/miscmath.py +835 -144
- rapidtide/multiproc.py +217 -44
- rapidtide/patchmatch.py +752 -0
- rapidtide/peakeval.py +32 -32
- rapidtide/ppgproc.py +2205 -0
- rapidtide/qualitycheck.py +353 -40
- rapidtide/refinedelay.py +854 -0
- rapidtide/refineregressor.py +939 -0
- rapidtide/resample.py +725 -204
- rapidtide/scripts/__init__.py +1 -0
- rapidtide/scripts/{adjustoffset → adjustoffset.py} +7 -2
- rapidtide/scripts/{aligntcs → aligntcs.py} +7 -2
- rapidtide/scripts/{applydlfilter → applydlfilter.py} +7 -2
- rapidtide/scripts/applyppgproc.py +28 -0
- rapidtide/scripts/{atlasaverage → atlasaverage.py} +7 -2
- rapidtide/scripts/{atlastool → atlastool.py} +7 -2
- rapidtide/scripts/{calcicc → calcicc.py} +7 -2
- rapidtide/scripts/{calctexticc → calctexticc.py} +7 -2
- rapidtide/scripts/{calcttest → calcttest.py} +7 -2
- rapidtide/scripts/{ccorrica → ccorrica.py} +7 -2
- rapidtide/scripts/delayvar.py +28 -0
- rapidtide/scripts/{diffrois → diffrois.py} +7 -2
- rapidtide/scripts/{endtidalproc → endtidalproc.py} +7 -2
- rapidtide/scripts/{fdica → fdica.py} +7 -2
- rapidtide/scripts/{filtnifti → filtnifti.py} +7 -2
- rapidtide/scripts/{filttc → filttc.py} +7 -2
- rapidtide/scripts/{fingerprint → fingerprint.py} +20 -16
- rapidtide/scripts/{fixtr → fixtr.py} +7 -2
- rapidtide/scripts/{gmscalc → gmscalc.py} +7 -2
- rapidtide/scripts/{happy → happy.py} +7 -2
- rapidtide/scripts/{happy2std → happy2std.py} +7 -2
- rapidtide/scripts/{happywarp → happywarp.py} +8 -4
- rapidtide/scripts/{histnifti → histnifti.py} +7 -2
- rapidtide/scripts/{histtc → histtc.py} +7 -2
- rapidtide/scripts/{glmfilt → linfitfilt.py} +7 -4
- rapidtide/scripts/{localflow → localflow.py} +7 -2
- rapidtide/scripts/{mergequality → mergequality.py} +7 -2
- rapidtide/scripts/{pairproc → pairproc.py} +7 -2
- rapidtide/scripts/{pairwisemergenifti → pairwisemergenifti.py} +7 -2
- rapidtide/scripts/{physiofreq → physiofreq.py} +7 -2
- rapidtide/scripts/{pixelcomp → pixelcomp.py} +7 -2
- rapidtide/scripts/{plethquality → plethquality.py} +7 -2
- rapidtide/scripts/{polyfitim → polyfitim.py} +7 -2
- rapidtide/scripts/{proj2flow → proj2flow.py} +7 -2
- rapidtide/scripts/{rankimage → rankimage.py} +7 -2
- rapidtide/scripts/{rapidtide → rapidtide.py} +7 -2
- rapidtide/scripts/{rapidtide2std → rapidtide2std.py} +7 -2
- rapidtide/scripts/{resamplenifti → resamplenifti.py} +7 -2
- rapidtide/scripts/{resampletc → resampletc.py} +7 -2
- rapidtide/scripts/retrolagtcs.py +28 -0
- rapidtide/scripts/retroregress.py +28 -0
- rapidtide/scripts/{roisummarize → roisummarize.py} +7 -2
- rapidtide/scripts/{runqualitycheck → runqualitycheck.py} +7 -2
- rapidtide/scripts/{showarbcorr → showarbcorr.py} +7 -2
- rapidtide/scripts/{showhist → showhist.py} +7 -2
- rapidtide/scripts/{showstxcorr → showstxcorr.py} +7 -2
- rapidtide/scripts/{showtc → showtc.py} +7 -2
- rapidtide/scripts/{showxcorr_legacy → showxcorr_legacy.py} +8 -8
- rapidtide/scripts/{showxcorrx → showxcorrx.py} +7 -2
- rapidtide/scripts/{showxy → showxy.py} +7 -2
- rapidtide/scripts/{simdata → simdata.py} +7 -2
- rapidtide/scripts/{spatialdecomp → spatialdecomp.py} +7 -2
- rapidtide/scripts/{spatialfit → spatialfit.py} +7 -2
- rapidtide/scripts/{spatialmi → spatialmi.py} +7 -2
- rapidtide/scripts/{spectrogram → spectrogram.py} +7 -2
- rapidtide/scripts/stupidramtricks.py +238 -0
- rapidtide/scripts/{synthASL → synthASL.py} +7 -2
- rapidtide/scripts/{tcfrom2col → tcfrom2col.py} +7 -2
- rapidtide/scripts/{tcfrom3col → tcfrom3col.py} +7 -2
- rapidtide/scripts/{temporaldecomp → temporaldecomp.py} +7 -2
- rapidtide/scripts/{testhrv → testhrv.py} +1 -1
- rapidtide/scripts/{threeD → threeD.py} +7 -2
- rapidtide/scripts/{tidepool → tidepool.py} +7 -2
- rapidtide/scripts/{variabilityizer → variabilityizer.py} +7 -2
- rapidtide/simFuncClasses.py +2113 -0
- rapidtide/simfuncfit.py +312 -108
- rapidtide/stats.py +579 -247
- rapidtide/tests/.coveragerc +27 -6
- rapidtide-2.9.6.data/scripts/fdica → rapidtide/tests/cleanposttest +4 -6
- rapidtide/tests/happycomp +9 -0
- rapidtide/tests/resethappytargets +1 -1
- rapidtide/tests/resetrapidtidetargets +1 -1
- rapidtide/tests/resettargets +1 -1
- rapidtide/tests/runlocaltest +3 -3
- rapidtide/tests/showkernels +1 -1
- rapidtide/tests/test_aliasedcorrelate.py +4 -4
- rapidtide/tests/test_aligntcs.py +1 -1
- rapidtide/tests/test_calcicc.py +1 -1
- rapidtide/tests/test_cleanregressor.py +184 -0
- rapidtide/tests/test_congrid.py +70 -81
- rapidtide/tests/test_correlate.py +1 -1
- rapidtide/tests/test_corrpass.py +4 -4
- rapidtide/tests/test_delayestimation.py +54 -59
- rapidtide/tests/test_dlfiltertorch.py +437 -0
- rapidtide/tests/test_doresample.py +2 -2
- rapidtide/tests/test_externaltools.py +69 -0
- rapidtide/tests/test_fastresampler.py +9 -5
- rapidtide/tests/test_filter.py +96 -57
- rapidtide/tests/test_findmaxlag.py +50 -19
- rapidtide/tests/test_fullrunhappy_v1.py +15 -10
- rapidtide/tests/test_fullrunhappy_v2.py +19 -13
- rapidtide/tests/test_fullrunhappy_v3.py +28 -13
- rapidtide/tests/test_fullrunhappy_v4.py +30 -11
- rapidtide/tests/test_fullrunhappy_v5.py +62 -0
- rapidtide/tests/test_fullrunrapidtide_v1.py +61 -7
- rapidtide/tests/test_fullrunrapidtide_v2.py +26 -14
- rapidtide/tests/test_fullrunrapidtide_v3.py +28 -8
- rapidtide/tests/test_fullrunrapidtide_v4.py +16 -8
- rapidtide/tests/test_fullrunrapidtide_v5.py +15 -6
- rapidtide/tests/test_fullrunrapidtide_v6.py +142 -0
- rapidtide/tests/test_fullrunrapidtide_v7.py +114 -0
- rapidtide/tests/test_fullrunrapidtide_v8.py +66 -0
- rapidtide/tests/test_getparsers.py +158 -0
- rapidtide/tests/test_io.py +59 -18
- rapidtide/tests/{test_glmpass.py → test_linfitfiltpass.py} +10 -10
- rapidtide/tests/test_mi.py +1 -1
- rapidtide/tests/test_miscmath.py +1 -1
- rapidtide/tests/test_motionregress.py +5 -5
- rapidtide/tests/test_nullcorr.py +6 -9
- rapidtide/tests/test_padvec.py +216 -0
- rapidtide/tests/test_parserfuncs.py +101 -0
- rapidtide/tests/test_phaseanalysis.py +1 -1
- rapidtide/tests/test_rapidtideparser.py +59 -53
- rapidtide/tests/test_refinedelay.py +296 -0
- rapidtide/tests/test_runmisc.py +5 -5
- rapidtide/tests/test_sharedmem.py +60 -0
- rapidtide/tests/test_simroundtrip.py +132 -0
- rapidtide/tests/test_simulate.py +1 -1
- rapidtide/tests/test_stcorrelate.py +4 -2
- rapidtide/tests/test_timeshift.py +2 -2
- rapidtide/tests/test_valtoindex.py +1 -1
- rapidtide/tests/test_zRapidtideDataset.py +5 -3
- rapidtide/tests/utils.py +10 -9
- rapidtide/tidepoolTemplate.py +88 -70
- rapidtide/tidepoolTemplate.ui +60 -46
- rapidtide/tidepoolTemplate_alt.py +88 -53
- rapidtide/tidepoolTemplate_alt.ui +62 -52
- rapidtide/tidepoolTemplate_alt_qt6.py +921 -0
- rapidtide/tidepoolTemplate_big.py +1125 -0
- rapidtide/tidepoolTemplate_big.ui +2386 -0
- rapidtide/tidepoolTemplate_big_qt6.py +1129 -0
- rapidtide/tidepoolTemplate_qt6.py +793 -0
- rapidtide/util.py +1389 -148
- rapidtide/voxelData.py +1048 -0
- rapidtide/wiener.py +138 -25
- rapidtide/wiener2.py +114 -8
- rapidtide/workflows/adjustoffset.py +107 -5
- rapidtide/workflows/aligntcs.py +86 -3
- rapidtide/workflows/applydlfilter.py +231 -89
- rapidtide/workflows/applyppgproc.py +540 -0
- rapidtide/workflows/atlasaverage.py +309 -48
- rapidtide/workflows/atlastool.py +130 -9
- rapidtide/workflows/calcSimFuncMap.py +490 -0
- rapidtide/workflows/calctexticc.py +202 -10
- rapidtide/workflows/ccorrica.py +123 -15
- rapidtide/workflows/cleanregressor.py +415 -0
- rapidtide/workflows/delayvar.py +1268 -0
- rapidtide/workflows/diffrois.py +84 -6
- rapidtide/workflows/endtidalproc.py +149 -9
- rapidtide/workflows/fdica.py +197 -17
- rapidtide/workflows/filtnifti.py +71 -4
- rapidtide/workflows/filttc.py +76 -5
- rapidtide/workflows/fitSimFuncMap.py +578 -0
- rapidtide/workflows/fixtr.py +74 -4
- rapidtide/workflows/gmscalc.py +116 -6
- rapidtide/workflows/happy.py +1242 -480
- rapidtide/workflows/happy2std.py +145 -13
- rapidtide/workflows/happy_parser.py +277 -59
- rapidtide/workflows/histnifti.py +120 -4
- rapidtide/workflows/histtc.py +85 -4
- rapidtide/workflows/{glmfilt.py → linfitfilt.py} +128 -14
- rapidtide/workflows/localflow.py +329 -29
- rapidtide/workflows/mergequality.py +80 -4
- rapidtide/workflows/niftidecomp.py +323 -19
- rapidtide/workflows/niftistats.py +178 -8
- rapidtide/workflows/pairproc.py +99 -5
- rapidtide/workflows/pairwisemergenifti.py +86 -3
- rapidtide/workflows/parser_funcs.py +1488 -56
- rapidtide/workflows/physiofreq.py +139 -12
- rapidtide/workflows/pixelcomp.py +211 -9
- rapidtide/workflows/plethquality.py +105 -23
- rapidtide/workflows/polyfitim.py +159 -19
- rapidtide/workflows/proj2flow.py +76 -3
- rapidtide/workflows/rankimage.py +115 -8
- rapidtide/workflows/rapidtide.py +1785 -1858
- rapidtide/workflows/rapidtide2std.py +101 -3
- rapidtide/workflows/rapidtide_parser.py +590 -389
- rapidtide/workflows/refineDelayMap.py +249 -0
- rapidtide/workflows/refineRegressor.py +1215 -0
- rapidtide/workflows/regressfrommaps.py +308 -0
- rapidtide/workflows/resamplenifti.py +86 -4
- rapidtide/workflows/resampletc.py +92 -4
- rapidtide/workflows/retrolagtcs.py +442 -0
- rapidtide/workflows/retroregress.py +1501 -0
- rapidtide/workflows/roisummarize.py +176 -7
- rapidtide/workflows/runqualitycheck.py +72 -7
- rapidtide/workflows/showarbcorr.py +172 -16
- rapidtide/workflows/showhist.py +87 -3
- rapidtide/workflows/showstxcorr.py +161 -4
- rapidtide/workflows/showtc.py +172 -10
- rapidtide/workflows/showxcorrx.py +250 -62
- rapidtide/workflows/showxy.py +186 -16
- rapidtide/workflows/simdata.py +418 -112
- rapidtide/workflows/spatialfit.py +83 -8
- rapidtide/workflows/spatialmi.py +252 -29
- rapidtide/workflows/spectrogram.py +306 -33
- rapidtide/workflows/synthASL.py +157 -6
- rapidtide/workflows/tcfrom2col.py +77 -3
- rapidtide/workflows/tcfrom3col.py +75 -3
- rapidtide/workflows/tidepool.py +3829 -666
- rapidtide/workflows/utils.py +45 -19
- rapidtide/workflows/utils_doc.py +293 -0
- rapidtide/workflows/variabilityizer.py +118 -5
- {rapidtide-2.9.6.dist-info → rapidtide-3.1.3.dist-info}/METADATA +30 -223
- rapidtide-3.1.3.dist-info/RECORD +393 -0
- {rapidtide-2.9.6.dist-info → rapidtide-3.1.3.dist-info}/WHEEL +1 -1
- rapidtide-3.1.3.dist-info/entry_points.txt +65 -0
- rapidtide-3.1.3.dist-info/top_level.txt +2 -0
- rapidtide/calcandfitcorrpairs.py +0 -262
- rapidtide/data/examples/src/testoutputsize +0 -45
- rapidtide/data/models/model_revised/model.h5 +0 -0
- rapidtide/data/models/model_serdar/model.h5 +0 -0
- rapidtide/data/models/model_serdar2/model.h5 +0 -0
- rapidtide/data/reference/ASPECTS_nlin_asym_09c_2mm.nii.gz +0 -0
- rapidtide/data/reference/ASPECTS_nlin_asym_09c_2mm_mask.nii.gz +0 -0
- rapidtide/data/reference/ATTbasedFlowTerritories_split_nlin_asym_09c_2mm.nii.gz +0 -0
- rapidtide/data/reference/ATTbasedFlowTerritories_split_nlin_asym_09c_2mm_mask.nii.gz +0 -0
- rapidtide/data/reference/HCP1200_binmask_2mm_2009c_asym.nii.gz +0 -0
- rapidtide/data/reference/HCP1200_lag_2mm_2009c_asym.nii.gz +0 -0
- rapidtide/data/reference/HCP1200_mask_2mm_2009c_asym.nii.gz +0 -0
- rapidtide/data/reference/HCP1200_negmask_2mm_2009c_asym.nii.gz +0 -0
- rapidtide/data/reference/HCP1200_sigma_2mm_2009c_asym.nii.gz +0 -0
- rapidtide/data/reference/HCP1200_strength_2mm_2009c_asym.nii.gz +0 -0
- rapidtide/glmpass.py +0 -434
- rapidtide/refine_factored.py +0 -641
- rapidtide/scripts/retroglm +0 -23
- rapidtide/workflows/glmfrommaps.py +0 -202
- rapidtide/workflows/retroglm.py +0 -643
- rapidtide-2.9.6.data/scripts/adjustoffset +0 -23
- rapidtide-2.9.6.data/scripts/aligntcs +0 -23
- rapidtide-2.9.6.data/scripts/applydlfilter +0 -23
- rapidtide-2.9.6.data/scripts/atlasaverage +0 -23
- rapidtide-2.9.6.data/scripts/atlastool +0 -23
- rapidtide-2.9.6.data/scripts/calcicc +0 -22
- rapidtide-2.9.6.data/scripts/calctexticc +0 -23
- rapidtide-2.9.6.data/scripts/calcttest +0 -22
- rapidtide-2.9.6.data/scripts/ccorrica +0 -23
- rapidtide-2.9.6.data/scripts/diffrois +0 -23
- rapidtide-2.9.6.data/scripts/endtidalproc +0 -23
- rapidtide-2.9.6.data/scripts/filtnifti +0 -23
- rapidtide-2.9.6.data/scripts/filttc +0 -23
- rapidtide-2.9.6.data/scripts/fingerprint +0 -593
- rapidtide-2.9.6.data/scripts/fixtr +0 -23
- rapidtide-2.9.6.data/scripts/glmfilt +0 -24
- rapidtide-2.9.6.data/scripts/gmscalc +0 -22
- rapidtide-2.9.6.data/scripts/happy +0 -25
- rapidtide-2.9.6.data/scripts/happy2std +0 -23
- rapidtide-2.9.6.data/scripts/happywarp +0 -350
- rapidtide-2.9.6.data/scripts/histnifti +0 -23
- rapidtide-2.9.6.data/scripts/histtc +0 -23
- rapidtide-2.9.6.data/scripts/localflow +0 -23
- rapidtide-2.9.6.data/scripts/mergequality +0 -23
- rapidtide-2.9.6.data/scripts/pairproc +0 -23
- rapidtide-2.9.6.data/scripts/pairwisemergenifti +0 -23
- rapidtide-2.9.6.data/scripts/physiofreq +0 -23
- rapidtide-2.9.6.data/scripts/pixelcomp +0 -23
- rapidtide-2.9.6.data/scripts/plethquality +0 -23
- rapidtide-2.9.6.data/scripts/polyfitim +0 -23
- rapidtide-2.9.6.data/scripts/proj2flow +0 -23
- rapidtide-2.9.6.data/scripts/rankimage +0 -23
- rapidtide-2.9.6.data/scripts/rapidtide +0 -23
- rapidtide-2.9.6.data/scripts/rapidtide2std +0 -23
- rapidtide-2.9.6.data/scripts/resamplenifti +0 -23
- rapidtide-2.9.6.data/scripts/resampletc +0 -23
- rapidtide-2.9.6.data/scripts/retroglm +0 -23
- rapidtide-2.9.6.data/scripts/roisummarize +0 -23
- rapidtide-2.9.6.data/scripts/runqualitycheck +0 -23
- rapidtide-2.9.6.data/scripts/showarbcorr +0 -23
- rapidtide-2.9.6.data/scripts/showhist +0 -23
- rapidtide-2.9.6.data/scripts/showstxcorr +0 -23
- rapidtide-2.9.6.data/scripts/showtc +0 -23
- rapidtide-2.9.6.data/scripts/showxcorr_legacy +0 -536
- rapidtide-2.9.6.data/scripts/showxcorrx +0 -23
- rapidtide-2.9.6.data/scripts/showxy +0 -23
- rapidtide-2.9.6.data/scripts/simdata +0 -23
- rapidtide-2.9.6.data/scripts/spatialdecomp +0 -23
- rapidtide-2.9.6.data/scripts/spatialfit +0 -23
- rapidtide-2.9.6.data/scripts/spatialmi +0 -23
- rapidtide-2.9.6.data/scripts/spectrogram +0 -23
- rapidtide-2.9.6.data/scripts/synthASL +0 -23
- rapidtide-2.9.6.data/scripts/tcfrom2col +0 -23
- rapidtide-2.9.6.data/scripts/tcfrom3col +0 -23
- rapidtide-2.9.6.data/scripts/temporaldecomp +0 -23
- rapidtide-2.9.6.data/scripts/threeD +0 -236
- rapidtide-2.9.6.data/scripts/tidepool +0 -23
- rapidtide-2.9.6.data/scripts/variabilityizer +0 -23
- rapidtide-2.9.6.dist-info/RECORD +0 -359
- rapidtide-2.9.6.dist-info/top_level.txt +0 -86
- {rapidtide-2.9.6.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-
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
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
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
-
|
|
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.
|
|
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,
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
-
|
|
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
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
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
|
-
|
|
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(
|
|
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}.
|
|
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
|
|
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
|
-
|
|
436
|
-
|
|
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
|
-
|
|
449
|
-
|
|
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(
|
|
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
|
|
468
|
-
weightarray = scaleddata
|
|
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
|
|
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.
|
|
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
|
-
"
|
|
529
|
-
"
|
|
530
|
-
"
|
|
531
|
-
"
|
|
532
|
-
"
|
|
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 =
|
|
558
|
-
|
|
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__(
|
|
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
|
-
"
|
|
605
|
-
"
|
|
606
|
-
"
|
|
607
|
-
"
|
|
608
|
-
"
|
|
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
|
-
"
|
|
678
|
-
"
|
|
679
|
-
"
|
|
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,
|
|
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
|
-
"
|
|
763
|
-
"
|
|
764
|
-
"
|
|
765
|
-
"
|
|
766
|
-
"
|
|
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
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
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
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
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.
|
|
2040
|
+
layersize = self.window_size
|
|
803
2041
|
nfilters = self.num_filters
|
|
804
|
-
|
|
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
|
-
#
|
|
821
|
-
for
|
|
822
|
-
|
|
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
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
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
|
-
|
|
854
|
-
|
|
855
|
-
self
|
|
856
|
-
|
|
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.
|
|
859
|
-
|
|
860
|
-
self.
|
|
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
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
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
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
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
|
-
"
|
|
899
|
-
"
|
|
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__(
|
|
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
|
-
"
|
|
957
|
-
"
|
|
958
|
-
"
|
|
959
|
-
"
|
|
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
|
|
1109
|
-
|
|
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
|
-
|
|
3031
|
+
if debug:
|
|
3032
|
+
print(f"searchstring: {searchstring} -> {fromfile}")
|
|
1112
3033
|
|
|
1113
|
-
# make sure all
|
|
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
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
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
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1158
|
-
|
|
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
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
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 =
|
|
1208
|
-
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
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="/
|
|
1295
|
-
inputfrag="abc",
|
|
1296
|
-
targetfrag="xyz",
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
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
|
-
|
|
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 =
|
|
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,
|