KeondoPark commited on
Commit
35f60b9
·
0 Parent(s):

Initial commit for public release

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +1 -0
  2. .gitignore +22 -0
  3. README.md +69 -0
  4. configs/Eval_6mod_CL_full_night.yaml +34 -0
  5. configs/Eval_6mod_CL_full_night_measure.yaml +34 -0
  6. configs/FT_6mod.yaml +36 -0
  7. configs/FT_6mod_CL.yaml +36 -0
  8. configs/FT_6mod_CL_abl1.yaml +36 -0
  9. configs/FT_6mod_CL_abl2.yaml +36 -0
  10. configs/FT_6mod_CL_abl3.yaml +36 -0
  11. configs/FT_6mod_CL_abl4.yaml +36 -0
  12. configs/FT_6mod_CL_ah.yaml +36 -0
  13. configs/FT_6mod_CL_fewshot_ah.yaml +36 -0
  14. configs/FT_6mod_CL_full_night.yaml +41 -0
  15. configs/FT_6mod_CL_full_night_abl1.yaml +39 -0
  16. configs/FT_6mod_CL_full_night_abl2.yaml +39 -0
  17. configs/FT_6mod_CL_full_night_abl3.yaml +39 -0
  18. configs/FT_6mod_CL_full_night_abl4.yaml +41 -0
  19. configs/FT_6mod_CL_full_night_age.yaml +40 -0
  20. configs/FT_6mod_CL_full_night_ahi.yaml +40 -0
  21. configs/FT_6mod_CL_full_night_dino.yaml +41 -0
  22. configs/FT_6mod_CL_full_night_fewshot.yaml +39 -0
  23. configs/FT_6mod_CL_full_night_lstm.yaml +41 -0
  24. configs/FT_6mod_CL_full_night_sex.yaml +40 -0
  25. configs/FT_6mod_CL_full_night_simclr.yaml +41 -0
  26. configs/FT_6mod_diag.yaml +41 -0
  27. configs/PT_6mod_5ds_CL_test.yaml +41 -0
  28. configs/PT_6mod_9ds_CL.yaml +41 -0
  29. configs/PT_6mod_9ds_CL_abl1.yaml +41 -0
  30. configs/PT_6mod_9ds_CL_abl2.yaml +41 -0
  31. configs/PT_6mod_9ds_CL_abl3.yaml +41 -0
  32. configs/PT_6mod_9ds_CL_abl4.yaml +41 -0
  33. configs/PT_6mod_9ds_CL_abl5.yaml +41 -0
  34. configs/PT_6mod_9ds_CL_abl6.yaml +42 -0
  35. configs/PTseq_6mod_CL_full_night.yaml +37 -0
  36. configs/PTseq_6mod_CL_full_night_abl1.yaml +36 -0
  37. configs/PTseq_6mod_CL_full_night_abl2.yaml +36 -0
  38. configs/PTseq_6mod_CL_full_night_abl3.yaml +36 -0
  39. configs/PTseq_6mod_CL_full_night_abl4.yaml +38 -0
  40. configs/PTseq_6mod_CL_full_night_dino.yaml +39 -0
  41. configs/PTseq_6mod_CL_full_night_simclr.yaml +38 -0
  42. configs/global_cfg.py +73 -0
  43. data/README.md +63 -0
  44. data/cfs_meta_data/split_data.py +51 -0
  45. data/cfs_meta_data/test.txt +201 -0
  46. data/cfs_meta_data/train.txt +418 -0
  47. data/cfs_meta_data/val.txt +50 -0
  48. data/cfs_preprocess.py +372 -0
  49. data/cfs_process_rawdata.py +291 -0
  50. data/data_augments.py +318 -0
.gitattributes ADDED
@@ -0,0 +1 @@
 
 
1
+ *.png filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *__pycache__*
2
+ *.ipynb
3
+ *.pyc
4
+ *.pyo
5
+ *.pyd
6
+ *.pkl
7
+ *.pkl.gz
8
+ *.h5
9
+ *.hdf5
10
+ *.csv
11
+ *.log
12
+ experiments/
13
+ wandb/
14
+ ckpt/
15
+ .ipynb_checkpoints/
16
+ lightning_logs/*
17
+ lightning_logs/
18
+ datasets
19
+ Notebooks/
20
+ embeddings/
21
+ figures/
22
+ ft_results/
README.md ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SleepMaMi
2
+ This is the code respository for **SleepMaMi: A Universal Sleep Foundation Model for Integrating Macro- and Micro-structures**
3
+
4
+ ## Abstract
5
+ >While the shift toward unified foundation models has revolutionized many deep learning domains, sleep medicine remains largely restricted to task-specific models that focus on localized micro-structure features. These approaches often neglect the rich, multi-modal context of Polysomnography (PSG) and fail to capture the global macro-structure of a full night's sleep. To address this, we introduce SleepMaMi, a Sleep Foundation Model engineered to master both hour-long sleep architectures and fine-grained signal morphologies. Our framework utilizes a hierarchical dual-encoder design: a Macro-Encoder to model full-night temporal dependencies and a Micro-Encoder to capture short-term characteristics from biosignals. Macro-Encoder is trained via Demographic-Guided Contrastive Learning, which aligns overnight sleep patterns with objective subject metadata, such as age and sex, to refine global representations. Micro-Encoder is optimized via a hybrid Masked Autoencoder (MAE) and multi-modal contrastive objective. Pre-trained on a massive corpus of >20,000 PSG recordings (15.8K hours), SleepMaMi outperforms existing foundation models across a diverse suite of downstream tasks, demonstrating superior generalizability and label-efficient adaptation for clinical sleep analysis.
6
+
7
+
8
+ ## Prerequisites
9
+ ```
10
+ conda create -n sleepmami python==3.9
11
+ conda activate sleepmami
12
+ pip install -r requirements.txt
13
+
14
+ # conda install -c "nvidia/label/cuda-12.1.1" cuda-nvcc cuda-cudart-dev libcublas-dev libcurand-dev # if necessary
15
+ pip install flash-attn==2.7.4.post1 --no-build-isolation --cache-dir /tmp/pip_cache
16
+ apt update
17
+ apt install libgl1-mesa-glx
18
+ pip install mamba-ssm==2.2.3.post2 --no-build-isolation
19
+ ```
20
+
21
+
22
+ ## Data preprocessing
23
+ Please prepare pretraining and finetuning data, following [README](data/README.md) in `data` directory.
24
+
25
+ ## Pretraining
26
+ ### Micro-Encoder pretraining
27
+ After pretraining dataset is prepared, prepare a config file(`*.yaml`) in `configs` directory.
28
+
29
+ Example config files are provided in `configs` directory.
30
+
31
+ Use the following command to start pretraining:
32
+ ```
33
+ python pretrain.py --config PT_6mod_9ds_CL
34
+ ```
35
+
36
+
37
+ ### Macro-Encoder pretraining
38
+ Similar to Micro-Encoder pretraining, prepare a config file in `configs` directory.
39
+
40
+ Then use the following command to start Macro-Encoder pretraining
41
+ ```
42
+ python pretrain_seq.py --config PTseq_6mod_9ds_CL_full_night
43
+ ```
44
+
45
+
46
+ ### Downstream tasks
47
+ After pretraining is completed, finetuning on downstream tasks can be done with the following command:
48
+ ```
49
+ python finetune.py --config FT_6mod_CL
50
+ ```
51
+ The config file should be located in `configs` directory. `ft_task` variable should be set to specify the finetuning task (e.g. sleep_staging, apnea_seg, diag, etc.)
52
+
53
+
54
+ ### Pretrained checkpoints and Inference
55
+ To be completed.
56
+
57
+
58
+ ## BibTeX
59
+ Please use the below bibtex when you reference our work!
60
+ ```
61
+ @inproceedings{
62
+ park2026sleepmami,
63
+ title={SleepMaMi: A Universal Sleep Foundation Model for Integrating Macro- and Micro-structures},
64
+ author={Park, Keondo and Na, Younghoon and Choi, You Rim and Ryu, Hyunwoo and Shin, Hyun-Woo and Kim, Hyung-Sin},
65
+ booktitle={Forty-third International Conference on Machine Learning},
66
+ year={2026},
67
+ url={https://openreview.net/forum?id=e9hvlHlUas}
68
+ }
69
+ ```
configs/Eval_6mod_CL_full_night.yaml ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: Eval_PTseq_p50_6mod_9ds_kissFix_diag_micro
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: diagnosis
10
+ patch_size: 50
11
+ num_classes: 6
12
+ num_workers: 6
13
+ loss: coxph
14
+ batch_size_v: 32
15
+ proportion_v: 1.0
16
+ gpus: [0]
17
+ num_experts: 4
18
+ num_experts_per: 2
19
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_kissFix_diag_micro-final.ckpt # PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
20
+ previous_run_id: null
21
+ previous_checkpoint: null
22
+ scheduler_name: CosineAnnealingLR
23
+ modalities: [
24
+ "EEG","EOG","ECG","RESP","EMG","SaO2"
25
+ ]
26
+ sig_len_target: 30
27
+ use_revin: True
28
+ full_night: True
29
+ from_seq_pretrain: True
30
+ seq_truncate: False
31
+ use_lstm: False
32
+ use_micro: True
33
+ save_results: True
34
+ save_emb: False
configs/Eval_6mod_CL_full_night_measure.yaml ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: Eval_PTseq_p50_6mod_9ds_kissFix
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ loss: wce
14
+ batch_size_v: 8
15
+ proportion_v: 1.0
16
+ gpus: [0]
17
+ num_experts: 4
18
+ num_experts_per: 2
19
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_kissFix-final.ckpt # PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
20
+ previous_run_id: null
21
+ previous_checkpoint: null
22
+ scheduler_name: CosineAnnealingLR
23
+ modalities: [
24
+ "EEG","EOG","ECG","RESP","EMG","SaO2"
25
+ ]
26
+ sig_len_target: 30
27
+ use_revin: True
28
+ full_night: True
29
+ from_seq_pretrain: True
30
+ seq_truncate: False
31
+ use_lstm: False
32
+ use_micro: False
33
+ save_results: False
34
+ save_emb: False
configs/FT_6mod.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_p100_10_6mod_cat
3
+ data_root: datasets
4
+ dataset: ['phy']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi
9
+ ft_task: sleep_staging
10
+ patch_sizes: [10,100]
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.002
14
+ layer_decay: 1.0
15
+ weight_decay: 0.05
16
+ num_epochs: 3
17
+ loss: wce
18
+ batch_size_t: 512
19
+ batch_size_v: 512
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: p100_10_6mod-final.ckpt
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","EMG","ECG","AIRFLOW","ABD"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
configs/FT_6mod_CL.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_p50_6mod_CL_shhs_CLonly_cat
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.004
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: wce
18
+ batch_size_t: 512
19
+ batch_size_v: 512
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: p50_6mod_CL_shhs_CLonly_cat-final.ckpt #p50_6mod_6ds_CL5-final.ckpt #p50_6mod_hier_2_2_lgonly_5ds_CL_nonmix5-final.ckpt # p25_6mod_hier_2_2_4_lgonly_5ds_CL_nonmix6-final.ckpt
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
configs/FT_6mod_CL_abl1.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_p50_6mod_noshared_shhs
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.004
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: wce
18
+ batch_size_t: 512
19
+ batch_size_v: 512
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: p50_6mod_noshared_shhs-final.ckpt #p50_6mod_6ds_CL5-final.ckpt #p50_6mod_hier_2_2_lgonly_5ds_CL_nonmix5-final.ckpt # p25_6mod_hier_2_2_4_lgonly_5ds_CL_nonmix6-final.ckpt
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
configs/FT_6mod_CL_abl2.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_p50_6mod_MAEonly_shhs
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.004
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: wce
18
+ batch_size_t: 512
19
+ batch_size_v: 512
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: p50_6mod_MAEonly_shhs-final.ckpt #p50_6mod_6ds_CL5-final.ckpt #p50_6mod_hier_2_2_lgonly_5ds_CL_nonmix5-final.ckpt # p25_6mod_hier_2_2_4_lgonly_5ds_CL_nonmix6-final.ckpt
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
configs/FT_6mod_CL_abl3.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_p50_6mod_MAEonly_noMoE_shhs
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.004
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: wce
18
+ batch_size_t: 512
19
+ batch_size_v: 512
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: p50_6mod_MAEonly_noMoE_shhs-final.ckpt #p50_6mod_6ds_CL5-final.ckpt #p50_6mod_hier_2_2_lgonly_5ds_CL_nonmix5-final.ckpt # p25_6mod_hier_2_2_4_lgonly_5ds_CL_nonmix6-final.ckpt
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
configs/FT_6mod_CL_abl4.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_p50_6mod_CL_shhs
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.004
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: wce
18
+ batch_size_t: 512
19
+ batch_size_v: 512
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: p50_6mod_CL_shhs-final.ckpt #p50_6mod_6ds_CL5-final.ckpt #p50_6mod_hier_2_2_lgonly_5ds_CL_nonmix5-final.ckpt # p25_6mod_hier_2_2_4_lgonly_5ds_CL_nonmix6-final.ckpt
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
configs/FT_6mod_CL_ah.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_p50_6mod_9ds_kissFix_ah_sof
3
+ data_root: datasets
4
+ datasets: ['sof']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi
9
+ ft_task: apnea_seg
10
+ patch_size: 50
11
+ num_classes: 2
12
+ num_workers: 6
13
+ lr: 0.004
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: wce
18
+ batch_size_t: 1024
19
+ batch_size_v: 1024
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: p50_6mod_9ds_kissFix-final.ckpt # p50_6mod_hier_2_2_lgonly_5ds_CL_nonmix2-final.ckpt # p25_6mod_hier_2_2_4_lgonly_5ds_CL_nonmix6-final.ckpt
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG", "SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
configs/FT_6mod_CL_fewshot_ah.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_p50_6mod_9ds_kissFix_ah_cfs_1_e20
3
+ data_root: datasets
4
+ datasets: ['cfs_1'] #['isruc_sg1_1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi
9
+ ft_task: apnea_seg
10
+ patch_size: 50
11
+ num_classes: 2
12
+ num_workers: 6
13
+ lr: 0.004
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 20
17
+ loss: wce
18
+ batch_size_t: 1024
19
+ batch_size_v: 1024
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: p50_6mod_9ds_kissFix-final.ckpt # PTseq_p50_6mod_6ds_CL5_5ds-epoch=00-train_loss=10.93.ckpt ## PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
configs/FT_6mod_CL_full_night.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_PTseq_p50_6mod_9ds_kissFix
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.01
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: wce
18
+ batch_size_t: 4
19
+ batch_size_v: 32
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_kissFix-final.ckpt # PTseq_p50_6mod_6ds_CL5_5ds-epoch=00-train_loss=10.93.ckpt ## PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
37
+ full_night: True
38
+ from_seq_pretrain: True
39
+ seq_truncate: False
40
+ use_micro: False
41
+ use_lstm: False
configs/FT_6mod_CL_full_night_abl1.yaml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_PTseq_p50_6mod_9ds_CL_w_1_improve_shhs_bmi2
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.01
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: wce
18
+ batch_size_t: 4
19
+ batch_size_v: 32
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_CL_w_1_improve_shhs_bmi2-final.ckpt # PTseq_p50_6mod_6ds_CL5_5ds-epoch=00-train_loss=10.93.ckpt ## PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
37
+ full_night: True
38
+ from_seq_pretrain: True
39
+ seq_truncate: False
configs/FT_6mod_CL_full_night_abl2.yaml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_PTseq_p50_6mod_9ds_CL_w_1_improve_shhs_age2
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.01
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: wce
18
+ batch_size_t: 4
19
+ batch_size_v: 32
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_CL_w_1_improve_shhs_age2-final.ckpt # PTseq_p50_6mod_6ds_CL5_5ds-epoch=00-train_loss=10.93.ckpt ## PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
37
+ full_night: True
38
+ from_seq_pretrain: True
39
+ seq_truncate: False
configs/FT_6mod_CL_full_night_abl3.yaml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_PTseq_p50_6mod_9ds_CL_w_1_shhs_sex
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.01
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: wce
18
+ batch_size_t: 4
19
+ batch_size_v: 32
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_CL_w_1_shhs_sex-final.ckpt # PTseq_p50_6mod_6ds_CL5_5ds-epoch=00-train_loss=10.93.ckpt ## PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
37
+ full_night: True
38
+ from_seq_pretrain: True
39
+ seq_truncate: False
configs/FT_6mod_CL_full_night_abl4.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_PTseq_p50_6mod_9ds_kissFix_shhs_mamba_uni
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.01
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: wce
18
+ batch_size_t: 32
19
+ batch_size_v: 32
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_kissFix_shhs_mamba_uni-final.ckpt # PTseq_p50_6mod_6ds_CL5_5ds-epoch=00-train_loss=10.93.ckpt ## PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
37
+ full_night: True
38
+ from_seq_pretrain: True
39
+ seq_truncate: False
40
+ use_transformer: False
41
+ bidi: False
configs/FT_6mod_CL_full_night_age.yaml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_PTseq_p50_6mod_9ds_CL_w_1_improve2_age
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: age
10
+ patch_size: 50
11
+ num_classes: 1
12
+ num_workers: 6
13
+ lr: 0.004
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: mae
18
+ batch_size_t: 16
19
+ batch_size_v: 32
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_CL_w_1_improve2-final.ckpt # PTseq_p50_6mod_6ds_CL5_5ds-epoch=00-train_loss=10.93.ckpt ## PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
37
+ full_night: True
38
+ from_seq_pretrain: True
39
+ seq_truncate: False
40
+ use_micro: False
configs/FT_6mod_CL_full_night_ahi.yaml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_PTseq_p50_6mod_9ds_CL_w_1_improve2_ahi_micro
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: ahi
10
+ patch_size: 50
11
+ num_classes: 1
12
+ num_workers: 6
13
+ lr: 0.004
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: mae
18
+ batch_size_t: 16
19
+ batch_size_v: 32
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_CL_w_1_improve2-final.ckpt # PTseq_p50_6mod_6ds_CL5_5ds-epoch=00-train_loss=10.93.ckpt ## PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
37
+ full_night: True
38
+ from_seq_pretrain: True
39
+ seq_truncate: False
40
+ use_micro: False
configs/FT_6mod_CL_full_night_dino.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_PTseq_p50_6mod_9ds_kissFix_dino
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.01
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: wce
18
+ batch_size_t: 4
19
+ batch_size_v: 32
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_kissFix_dino-final.ckpt # PTseq_p50_6mod_6ds_CL5_5ds-epoch=00-train_loss=10.93.ckpt ## PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
37
+ full_night: True
38
+ from_seq_pretrain: True
39
+ seq_truncate: False
40
+ use_micro: False
41
+ use_lstm: False
configs/FT_6mod_CL_full_night_fewshot.yaml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_PTseq_p50_6mod_9ds_kissFix_cfs_100_e20
3
+ data_root: datasets
4
+ datasets: ['cfs_100'] #['isruc_sg1_1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.01
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 20
17
+ loss: wce
18
+ batch_size_t: 5
19
+ batch_size_v: 32
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_kissFix-final.ckpt # PTseq_p50_6mod_6ds_CL5_5ds-epoch=00-train_loss=10.93.ckpt ## PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
37
+ full_night: True
38
+ from_seq_pretrain: True
39
+ seq_truncate: False
configs/FT_6mod_CL_full_night_lstm.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_PTseq_p50_6mod_9ds_kissFix_cfs_lstm
3
+ data_root: datasets
4
+ datasets: ['cfs']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.001
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 20
17
+ loss: wce
18
+ batch_size_t: 4
19
+ batch_size_v: 32
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_kissFix-final.ckpt # PTseq_p50_6mod_6ds_CL5_5ds-epoch=00-train_loss=10.93.ckpt ## PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
37
+ full_night: True
38
+ from_seq_pretrain: True
39
+ seq_truncate: False
40
+ use_micro: False
41
+ use_lstm: True
configs/FT_6mod_CL_full_night_sex.yaml ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_PTseq_p50_6mod_9ds_CL_w_1_improve2_sex
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: sex
10
+ patch_size: 50
11
+ num_classes: 2
12
+ num_workers: 6
13
+ lr: 0.004
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: ce
18
+ batch_size_t: 8
19
+ batch_size_v: 32
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_CL_w_1_improve2-final.ckpt # PTseq_p50_6mod_6ds_CL5_5ds-epoch=00-train_loss=10.93.ckpt ## PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
37
+ full_night: True
38
+ from_seq_pretrain: True
39
+ seq_truncate: False
40
+ use_micro: False
configs/FT_6mod_CL_full_night_simclr.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: FT_PTseq_p50_6mod_9ds_kissFix_simclr2
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: sleep_staging
10
+ patch_size: 50
11
+ num_classes: 5
12
+ num_workers: 6
13
+ lr: 0.01
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: wce
18
+ batch_size_t: 4
19
+ batch_size_v: 32
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_kissFix_simclr2-final.ckpt # PTseq_p50_6mod_6ds_CL5_5ds-epoch=00-train_loss=10.93.ckpt ## PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
37
+ full_night: True
38
+ from_seq_pretrain: True
39
+ seq_truncate: False
40
+ use_micro: False
41
+ use_lstm: False
configs/FT_6mod_diag.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_FT
2
+ experiment_name: PTseq_p50_6mod_9ds_CL_w_1_improve_diag
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ ft_task: diagnosis
10
+ patch_size: 50
11
+ num_classes: 6
12
+ num_workers: 6
13
+ lr: 0.01
14
+ layer_decay: 1.0
15
+ weight_decay: 0.0001
16
+ num_epochs: 3
17
+ loss: coxph
18
+ batch_size_t: 4
19
+ batch_size_v: 32
20
+ proportion_t: 1.0
21
+ proportion_v: 1.0
22
+ optimizer_name: AdamW
23
+ gpus: [0,1]
24
+ accumulate_grad_batches: 1
25
+ num_experts: 4
26
+ num_experts_per: 2
27
+ pretrain_checkpoint: PTseq_p50_6mod_9ds_CL_w_1_improve-final.ckpt # PTseq_p50_4mod_hier_2_2_lgonly_4ds_CL_koelo_full_night-final.ckpt # p50_4mod_hier_2_2_lgonly_4ds_CL_koelo-final.ckpt #
28
+ previous_run_id: null
29
+ previous_checkpoint: null
30
+ scheduler_name: CosineAnnealingLR
31
+ modalities: [
32
+ "EEG","EOG","ECG","RESP","EMG","SaO2"
33
+ ]
34
+ sig_len_target: 30
35
+ full_finetune: False
36
+ use_revin: True
37
+ full_night: True
38
+ from_seq_pretrain: True
39
+ seq_truncate: False
40
+ use_lstm: False
41
+ use_micro: False
configs/PT_6mod_5ds_CL_test.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_3
2
+ experiment_name: p50_6mod_kiss_CL_w_1_test
3
+ data_root: datasets
4
+ datasets: ['kiss'] #['phy-tr','phy-te','shhs1','shhs2','kiss','kvss','mros1','mros1-val','mros1-te','mros2','mros2-val','mros2-te','mesa','mesa-val','mesa-te']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: convmae1d_multi
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 6
12
+ lr: 0.0005
13
+ weight_decay: 0.05
14
+ num_epochs: 1
15
+ batch_size_t: 1
16
+ proportion_t: 1.0
17
+ optimizer_name: AdamW
18
+ gpus: [0]
19
+ accumulate_grad_batches: 1
20
+ num_experts: 4
21
+ num_experts_per: 2
22
+ previous_run_id: null
23
+ previous_checkpoint: null
24
+ pretrained: null #experiments/p50_6mod_hier_2_2_lgonly_5ds_CL_nonmix8-final.ckpt
25
+ scheduler_name: CosineAnnealingLR
26
+ modalities: [
27
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
28
+ ]
29
+ lg_ratio: 1.0
30
+ sig_len_target: 60
31
+ use_shared: True
32
+ use_moe: True
33
+ use_revin: True
34
+ loss: MSE
35
+ loss_weights: {
36
+ 'mae': 1.0,
37
+ 'moe': 0.001,
38
+ 'ortho': 0.0,
39
+ 'contrastive': 0.1,
40
+ 'koleo': 0.01
41
+ }
configs/PT_6mod_9ds_CL.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_3
2
+ experiment_name: p50_6mod_9ds_kissFix
3
+ data_root: datasets
4
+ datasets: ['phy-tr','phy-te','shhs1','shhs2','kiss','kvss','mros1','mros1-val','mros1-te','mros2','mros2-val','mros2-te','mesa','mesa-val','mesa-te']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: convmae1d_multi
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 6
12
+ lr: 0.0005
13
+ weight_decay: 0.05
14
+ num_epochs: 2
15
+ batch_size_t: 512
16
+ proportion_t: 1.0
17
+ optimizer_name: AdamW
18
+ gpus: [0,1]
19
+ accumulate_grad_batches: 1
20
+ num_experts: 4
21
+ num_experts_per: 2
22
+ previous_run_id: null
23
+ previous_checkpoint: null
24
+ pretrained: null #experiments/p50_6mod_hier_2_2_lgonly_5ds_CL_nonmix8-final.ckpt
25
+ scheduler_name: CosineAnnealingLR
26
+ modalities: [
27
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
28
+ ]
29
+ lg_ratio: 1.0
30
+ sig_len_target: 60
31
+ use_shared: True
32
+ use_moe: True
33
+ use_revin: True
34
+ loss: MSE
35
+ loss_weights: {
36
+ 'mae': 1.0,
37
+ 'moe': 0.001,
38
+ 'ortho': 0.0,
39
+ 'contrastive': 0.1,
40
+ 'koleo': 0.01
41
+ }
configs/PT_6mod_9ds_CL_abl1.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_3
2
+ experiment_name: p50_6mod_noshared_shhs
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: convmae1d_multi
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 6
12
+ lr: 0.0005
13
+ weight_decay: 0.05
14
+ num_epochs: 2
15
+ batch_size_t: 512
16
+ proportion_t: 1.0
17
+ optimizer_name: AdamW
18
+ gpus: [0,1]
19
+ accumulate_grad_batches: 1
20
+ num_experts: 4
21
+ num_experts_per: 2
22
+ previous_run_id: null
23
+ previous_checkpoint: null
24
+ pretrained: null #experiments/p50_6mod_hier_2_2_lgonly_5ds_CL_nonmix8-final.ckpt
25
+ scheduler_name: CosineAnnealingLR
26
+ modalities: [
27
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
28
+ ]
29
+ lg_ratio: 1.0
30
+ sig_len_target: 60
31
+ use_shared: False
32
+ use_moe: False
33
+ use_revin: True
34
+ loss: MSE
35
+ loss_weights: {
36
+ 'mae': 1.0,
37
+ 'moe': 0.0,
38
+ 'ortho': 0.0,
39
+ 'contrastive': 0.0,
40
+ 'koleo': 0.0
41
+ }
configs/PT_6mod_9ds_CL_abl2.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_3
2
+ experiment_name: p50_6mod_MAEonly_shhs
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: convmae1d_multi
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 6
12
+ lr: 0.0005
13
+ weight_decay: 0.05
14
+ num_epochs: 2
15
+ batch_size_t: 512
16
+ proportion_t: 1.0
17
+ optimizer_name: AdamW
18
+ gpus: [0,1]
19
+ accumulate_grad_batches: 1
20
+ num_experts: 4
21
+ num_experts_per: 2
22
+ previous_run_id: null
23
+ previous_checkpoint: null
24
+ pretrained: null #experiments/p50_6mod_hier_2_2_lgonly_5ds_CL_nonmix8-final.ckpt
25
+ scheduler_name: CosineAnnealingLR
26
+ modalities: [
27
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
28
+ ]
29
+ lg_ratio: 1.0
30
+ sig_len_target: 60
31
+ use_shared: True
32
+ use_moe: True
33
+ use_revin: True
34
+ loss: MSE
35
+ loss_weights: {
36
+ 'mae': 1.0,
37
+ 'moe': 0.001,
38
+ 'ortho': 0.0,
39
+ 'contrastive': 0.0,
40
+ 'koleo': 0.0
41
+ }
configs/PT_6mod_9ds_CL_abl3.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_3
2
+ experiment_name: p50_6mod_MAEonly_noMoE_shhs
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: convmae1d_multi
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 6
12
+ lr: 0.0005
13
+ weight_decay: 0.05
14
+ num_epochs: 2
15
+ batch_size_t: 512
16
+ proportion_t: 1.0
17
+ optimizer_name: AdamW
18
+ gpus: [0,1]
19
+ accumulate_grad_batches: 1
20
+ num_experts: 4
21
+ num_experts_per: 2
22
+ previous_run_id: null
23
+ previous_checkpoint: null
24
+ pretrained: null #experiments/p50_6mod_hier_2_2_lgonly_5ds_CL_nonmix8-final.ckpt
25
+ scheduler_name: CosineAnnealingLR
26
+ modalities: [
27
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
28
+ ]
29
+ lg_ratio: 1.0
30
+ sig_len_target: 60
31
+ use_shared: True
32
+ use_moe: False
33
+ use_revin: True
34
+ loss: MSE
35
+ loss_weights: {
36
+ 'mae': 1.0,
37
+ 'moe': 0.0,
38
+ 'ortho': 0.0,
39
+ 'contrastive': 0.0,
40
+ 'koleo': 0.0
41
+ }
configs/PT_6mod_9ds_CL_abl4.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_3
2
+ experiment_name: p50_6mod_CL_shhs
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: convmae1d_multi
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 6
12
+ lr: 0.0005
13
+ weight_decay: 0.05
14
+ num_epochs: 2
15
+ batch_size_t: 512
16
+ proportion_t: 1.0
17
+ optimizer_name: AdamW
18
+ gpus: [0,1]
19
+ accumulate_grad_batches: 1
20
+ num_experts: 4
21
+ num_experts_per: 2
22
+ previous_run_id: null
23
+ previous_checkpoint: null
24
+ pretrained: null #experiments/p50_6mod_hier_2_2_lgonly_5ds_CL_nonmix8-final.ckpt
25
+ scheduler_name: CosineAnnealingLR
26
+ modalities: [
27
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
28
+ ]
29
+ lg_ratio: 1.0
30
+ sig_len_target: 60
31
+ use_shared: True
32
+ use_moe: True
33
+ use_revin: True
34
+ loss: MSE
35
+ loss_weights: {
36
+ 'mae': 1.0,
37
+ 'moe': 0.001,
38
+ 'ortho': 0.0,
39
+ 'contrastive': 0.1,
40
+ 'koleo': 0.01
41
+ }
configs/PT_6mod_9ds_CL_abl5.yaml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_3
2
+ experiment_name: p50_6mod_CL_shhs_w3
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: convmae1d_multi
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 6
12
+ lr: 0.0005
13
+ weight_decay: 0.05
14
+ num_epochs: 2
15
+ batch_size_t: 512
16
+ proportion_t: 1.0
17
+ optimizer_name: AdamW
18
+ gpus: [0,1]
19
+ accumulate_grad_batches: 1
20
+ num_experts: 4
21
+ num_experts_per: 2
22
+ previous_run_id: null
23
+ previous_checkpoint: null
24
+ pretrained: null #experiments/p50_6mod_hier_2_2_lgonly_5ds_CL_nonmix8-final.ckpt
25
+ scheduler_name: CosineAnnealingLR
26
+ modalities: [
27
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
28
+ ]
29
+ lg_ratio: 1.0
30
+ sig_len_target: 60
31
+ use_shared: True
32
+ use_moe: True
33
+ use_revin: True
34
+ loss: MSE
35
+ loss_weights: {
36
+ 'mae': 1.0,
37
+ 'moe': 0.001,
38
+ 'ortho': 0.0,
39
+ 'contrastive': 0.3,
40
+ 'koleo': 0.01
41
+ }
configs/PT_6mod_9ds_CL_abl6.yaml ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_3
2
+ experiment_name: p50_6mod_CL_shhs_CLonly_cat
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: convmae1d_multi
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 6
12
+ lr: 0.0005
13
+ weight_decay: 0.05
14
+ num_epochs: 2
15
+ batch_size_t: 512
16
+ proportion_t: 1.0
17
+ optimizer_name: AdamW
18
+ gpus: [0,1]
19
+ accumulate_grad_batches: 1
20
+ num_experts: 4
21
+ num_experts_per: 2
22
+ previous_run_id: null
23
+ previous_checkpoint: null
24
+ pretrained: null #experiments/p50_6mod_hier_2_2_lgonly_5ds_CL_nonmix8-final.ckpt
25
+ scheduler_name: CosineAnnealingLR
26
+ modalities: [
27
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
28
+ ]
29
+ lg_ratio: 1.0
30
+ sig_len_target: 60
31
+ use_shared: True
32
+ use_moe: True
33
+ use_revin: True
34
+ loss: MSE
35
+ loss_weights: {
36
+ 'mae': 0.0,
37
+ 'moe': 0.001,
38
+ 'ortho': 0.0,
39
+ 'contrastive': 1.0,
40
+ 'koleo': 0.1
41
+ }
42
+ mask_ratio: 0.0
configs/PTseq_6mod_CL_full_night.yaml ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_PTseq
2
+ experiment_name: PTseq_p50_6mod_9ds_kissFix
3
+ data_root: datasets
4
+ datasets: ['shhs1','shhs2','kiss','kvss','mesa','mesa-val','mesa-te','mros1','mros1-val','mros1-te','mros2','mros2-val','mros2-te'] #'phy-te','mros1'] #
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 8
12
+ lr: 0.0001
13
+ layer_decay: 1.0
14
+ weight_decay: 0.05
15
+ num_epochs: 4
16
+ batch_size_t: 40
17
+ proportion_t: 1.0
18
+ optimizer_name: AdamW
19
+ gpus: [0,1]
20
+ accumulate_grad_batches: 1
21
+ num_experts: 4
22
+ num_experts_per: 2
23
+ pretrain_checkpoint: p50_6mod_9ds_kissFix-final.ckpt #p50_6mod_6ds_CL_w_1-final.ckpt
24
+ previous_run_id: null
25
+ previous_checkpoint: null
26
+ scheduler_name: WarmupCosineAnnealingLR
27
+ modalities: [
28
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
29
+ ]
30
+ sig_len_target: 30
31
+ full_finetune: False
32
+ use_revin: True
33
+ full_night: True
34
+ seq_truncate: True
35
+ demo_keys: ['age','sex','bmi']
36
+ cycle_len: 180
37
+ use_transformer: False
configs/PTseq_6mod_CL_full_night_abl1.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_PTseq
2
+ experiment_name: PTseq_p50_6mod_9ds_CL_w_1_improve_shhs_bmi2
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 8
12
+ lr: 0.0001
13
+ layer_decay: 1.0
14
+ weight_decay: 0.05
15
+ num_epochs: 4
16
+ batch_size_t: 40
17
+ proportion_t: 1.0
18
+ optimizer_name: AdamW
19
+ gpus: [0,1]
20
+ accumulate_grad_batches: 1
21
+ num_experts: 4
22
+ num_experts_per: 2
23
+ pretrain_checkpoint: p50_6mod_9ds_CL_w_1-final.ckpt #p50_6mod_6ds_CL_w_1-final.ckpt
24
+ previous_run_id: null
25
+ previous_checkpoint: null
26
+ scheduler_name: WarmupCosineAnnealingLR
27
+ modalities: [
28
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
29
+ ]
30
+ sig_len_target: 30
31
+ full_finetune: False
32
+ use_revin: True
33
+ full_night: True
34
+ seq_truncate: True
35
+ demo_keys: ['age','sex','bmi']
36
+ cycle_len: 180
configs/PTseq_6mod_CL_full_night_abl2.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_PTseq
2
+ experiment_name: PTseq_p50_6mod_9ds_CL_w_1_improve_shhs_age2
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 8
12
+ lr: 0.0001
13
+ layer_decay: 1.0
14
+ weight_decay: 0.05
15
+ num_epochs: 4
16
+ batch_size_t: 40
17
+ proportion_t: 1.0
18
+ optimizer_name: AdamW
19
+ gpus: [0,1]
20
+ accumulate_grad_batches: 1
21
+ num_experts: 4
22
+ num_experts_per: 2
23
+ pretrain_checkpoint: p50_6mod_9ds_CL_w_1-final.ckpt #p50_6mod_6ds_CL_w_1-final.ckpt
24
+ previous_run_id: null
25
+ previous_checkpoint: null
26
+ scheduler_name: WarmupCosineAnnealingLR
27
+ modalities: [
28
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
29
+ ]
30
+ sig_len_target: 30
31
+ full_finetune: False
32
+ use_revin: True
33
+ full_night: True
34
+ seq_truncate: True
35
+ demo_keys: ['age','sex','bmi']
36
+ cycle_len: 180
configs/PTseq_6mod_CL_full_night_abl3.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_PTseq
2
+ experiment_name: PTseq_p50_6mod_9ds_kissFix_shhs_cycle1080
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 8
12
+ lr: 0.0001
13
+ layer_decay: 1.0
14
+ weight_decay: 0.05
15
+ num_epochs: 4
16
+ batch_size_t: 40
17
+ proportion_t: 1.0
18
+ optimizer_name: AdamW
19
+ gpus: [0,1]
20
+ accumulate_grad_batches: 1
21
+ num_experts: 4
22
+ num_experts_per: 2
23
+ pretrain_checkpoint: p50_6mod_9ds_kissFix-final.ckpt #p50_6mod_6ds_CL_w_1-final.ckpt
24
+ previous_run_id: null
25
+ previous_checkpoint: null
26
+ scheduler_name: WarmupCosineAnnealingLR
27
+ modalities: [
28
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
29
+ ]
30
+ sig_len_target: 30
31
+ full_finetune: False
32
+ use_revin: True
33
+ full_night: True
34
+ seq_truncate: True
35
+ demo_keys: ['age','sex','bmi']
36
+ cycle_len: 1080
configs/PTseq_6mod_CL_full_night_abl4.yaml ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_PTseq
2
+ experiment_name: PTseq_p50_6mod_9ds_kissFix_shhs_mamba_uni
3
+ data_root: datasets
4
+ datasets: ['shhs1']
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 8
12
+ lr: 0.0001
13
+ layer_decay: 1.0
14
+ weight_decay: 0.05
15
+ num_epochs: 4
16
+ batch_size_t: 32
17
+ proportion_t: 1.0
18
+ optimizer_name: AdamW
19
+ gpus: [0]
20
+ accumulate_grad_batches: 1
21
+ num_experts: 4
22
+ num_experts_per: 2
23
+ pretrain_checkpoint: p50_6mod_9ds_kissFix-final.ckpt #p50_6mod_6ds_CL_w_1-final.ckpt
24
+ previous_run_id: null
25
+ previous_checkpoint: null
26
+ scheduler_name: WarmupCosineAnnealingLR
27
+ modalities: [
28
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
29
+ ]
30
+ sig_len_target: 30
31
+ full_finetune: False
32
+ use_revin: True
33
+ full_night: True
34
+ seq_truncate: True
35
+ demo_keys: ['age','sex','bmi']
36
+ cycle_len: 180
37
+ use_transformer: False
38
+ bidi: False
configs/PTseq_6mod_CL_full_night_dino.yaml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_PTseq
2
+ experiment_name: PTseq_p50_6mod_9ds_kissFix_dino
3
+ data_root: datasets
4
+ datasets: ['shhs1','shhs2','kiss','kvss','mesa','mesa-val','mesa-te','mros1','mros1-val','mros1-te','mros2','mros2-val','mros2-te'] #'phy-te','mros1'] #
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 8
12
+ lr: 0.0001
13
+ layer_decay: 1.0
14
+ weight_decay: 0.05
15
+ num_epochs: 4
16
+ batch_size_t: 24
17
+ proportion_t: 1.0
18
+ optimizer_name: AdamW
19
+ gpus: [0,1]
20
+ accumulate_grad_batches: 1
21
+ num_experts: 4
22
+ num_experts_per: 2
23
+ pretrain_checkpoint: p50_6mod_9ds_kissFix-final.ckpt #p50_6mod_6ds_CL_w_1-final.ckpt
24
+ previous_run_id: null
25
+ previous_checkpoint: null
26
+ scheduler_name: WarmupCosineAnnealingLR
27
+ modalities: [
28
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
29
+ ]
30
+ sig_len_target: 30
31
+ full_finetune: False
32
+ use_revin: True
33
+ full_night: True
34
+ seq_truncate: True
35
+ demo_keys: ['age','sex','bmi']
36
+ cycle_len: 180
37
+ use_transformer: False
38
+ simclr: False
39
+ dino: True
configs/PTseq_6mod_CL_full_night_simclr.yaml ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project_name: ConvMAE1d_PTseq
2
+ experiment_name: PTseq_p50_6mod_9ds_kissFix_simclr2
3
+ data_root: datasets
4
+ datasets: ['shhs1','shhs2','kiss','kvss','mesa','mesa-val','mesa-te','mros1','mros1-val','mros1-te','mros2','mros2-val','mros2-te'] #'phy-te','mros1'] #
5
+ config_save_path: experiments
6
+ results_save_path: experiments
7
+ ckpt_save_path: experiments
8
+ model_name: classification_multi_full_night
9
+ patch_size: 50
10
+ num_classes: 5
11
+ num_workers: 8
12
+ lr: 0.0001
13
+ layer_decay: 1.0
14
+ weight_decay: 0.05
15
+ num_epochs: 4
16
+ batch_size_t: 24
17
+ proportion_t: 1.0
18
+ optimizer_name: AdamW
19
+ gpus: [0,1]
20
+ accumulate_grad_batches: 1
21
+ num_experts: 4
22
+ num_experts_per: 2
23
+ pretrain_checkpoint: p50_6mod_9ds_kissFix-final.ckpt #p50_6mod_6ds_CL_w_1-final.ckpt
24
+ previous_run_id: null
25
+ previous_checkpoint: null
26
+ scheduler_name: WarmupCosineAnnealingLR
27
+ modalities: [
28
+ "EEG","EOG","ECG","RESP", "EMG" ,"SaO2"
29
+ ]
30
+ sig_len_target: 30
31
+ full_finetune: False
32
+ use_revin: True
33
+ full_night: True
34
+ seq_truncate: True
35
+ demo_keys: ['age','sex','bmi']
36
+ cycle_len: 180
37
+ use_transformer: False
38
+ simclr: True
configs/global_cfg.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ TARGET_RESAMPLE=100
2
+ EPOCH_LEN_MAX=1080
3
+ EPOCH_LEN_MIN=360
4
+ DATASET_PATH = {
5
+ 'phy-tr': 'physionet_2018/mmap_signals_MAE_processed',
6
+ 'phy-te': 'physionet_test/mmap_signals_MAE_processed',
7
+ 'shhs1': 'shhs1/mmap_signals_MAE_processed',
8
+ 'shhs2': 'shhs2/mmap_signals_MAE_processed',
9
+ 'kiss': 'kiss/mmap_signals_MAE_processed',
10
+ 'kvss': 'kvss/mmap_signals_MAE_processed',
11
+ 'mros1': 'mros1/mmap_signals_MAE_processed',
12
+ 'mros2': 'mros2/mmap_signals_MAE_processed',
13
+ 'mesa': 'mesa/mmap_signals_MAE_processed',
14
+ 'mros1-val': 'mros1_val',
15
+ 'mros1-te': 'mros1_te',
16
+ 'mros2-val': 'mros2_val',
17
+ 'mros2-te': 'mros2_te',
18
+ 'mesa-val': 'mesa_val',
19
+ 'mesa-te': 'mesa_te',
20
+ 'isruc_sg1': 'isruc_all/mmap_signals_MAE_processed',
21
+ 'isruc_sg1_1': 'isruc_all/mmap_signals_MAE_processed_train1',
22
+ 'isruc_sg1_5': 'isruc_all/mmap_signals_MAE_processed_train5',
23
+ 'isruc_sg1_10': 'isruc_all/mmap_signals_MAE_processed_train10',
24
+ 'isruc_sg1_20': 'isruc_all/mmap_signals_MAE_processed_train20',
25
+ 'isruc_sg1_30': 'isruc_all/mmap_signals_MAE_processed_train30',
26
+ 'isruc_sg1_50': 'isruc_all/mmap_signals_MAE_processed_train50',
27
+ 'cfs': 'cfs/mmap_signals_MAE_processed',
28
+ 'cfs_1': 'cfs/mmap_signals_MAE_processed_train1',
29
+ 'cfs_5': 'cfs/mmap_signals_MAE_processed_train5',
30
+ 'cfs_10': 'cfs/mmap_signals_MAE_processed_train10',
31
+ 'cfs_30': 'cfs/mmap_signals_MAE_processed_train30',
32
+ 'cfs_100': 'cfs/mmap_signals_MAE_processed_train100',
33
+ 'sof': 'sof/mmap_signals_MAE_processed',
34
+
35
+ }
36
+ LABELS_PATH = {
37
+ 'sleep_staging': {
38
+ 'phy-tr': 'physionet_2018/annotations',
39
+ 'shhs1': 'shhs1/annotations_split',
40
+ 'kiss': 'kiss/annotations_split',
41
+ 'isruc_sg1': 'isruc_all/annotations',
42
+ 'isruc_sg1_1': 'isruc_all/annotations',
43
+ 'isruc_sg1_5': 'isruc_all/annotations',
44
+ 'isruc_sg1_10': 'isruc_all/annotations',
45
+ 'isruc_sg1_20': 'isruc_all/annotations',
46
+ 'isruc_sg1_30': 'isruc_all/annotations',
47
+ 'isruc_sg1_50': 'isruc_all/annotations',
48
+ 'cfs': 'cfs/annotations_split',
49
+ 'cfs_1': 'cfs/annotations',
50
+ 'cfs_5': 'cfs/annotations',
51
+ 'cfs_10': 'cfs/annotations',
52
+ 'cfs_30': 'cfs/annotations',
53
+ 'cfs_100': 'cfs/annotations',
54
+ 'sof': 'sof/annotations',
55
+ },
56
+ 'apnea_seg': {
57
+ 'phy-tr': 'physionet_2018/ah_labels',
58
+ 'kiss': 'kiss/ah_labels_split',
59
+ 'shhs1': 'shhs1/ah_labels_split',
60
+ 'cfs': 'cfs/ah_labels_split',
61
+ 'cfs_1': 'cfs/ah_labels',
62
+ 'cfs_5': 'cfs/ah_labels',
63
+ 'cfs_10': 'cfs/ah_labels',
64
+ 'cfs_30': 'cfs/ah_labels',
65
+ 'cfs_100': 'cfs/ah_labels',
66
+ 'sof': 'sof/ah_labels',
67
+
68
+ }
69
+ }
70
+
71
+
72
+ CLASSIFICATION_TASKS = ['sleep_staging', 'apnea_seg', 'sex']
73
+ REGRESSION_TASKS = ['age', 'ahi']
data/README.md ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Data Preprocessing
2
+
3
+ This directory contains the preprocessing pipeline for several sleep study datasets, including **Physionet 2018, SHHS1/2, KISS/KVSS, MrOS1/2, and MESA**.
4
+
5
+ ---
6
+
7
+ ## 1. Raw Data Extraction
8
+ ### `{dataset_name}_process_rawdata.py`
9
+
10
+ This script extracts signals and labels from raw data (e.g., `.edf` files) and saves them in `.npy` format.
11
+
12
+ * **Channel Selection:** Extracts specific required channels: `EEG`, `EOG`, `EMG`, `ECG`, `ABD`, `CHEST`, `AIRFLOW`, and `SaO2`.
13
+ * **Label Alignment:** * Synchronizes sleep staging labels with signal timeframes.
14
+ * Adjusts staging formats (e.g., converting **R&K** to **AASM** standards).
15
+ * Excludes error cases or undefined stages (e.g., "Unknown").
16
+ * **Respiratory Events:** Extracts Apnea-Hypopnea labels where applicable (Apnea: 2, Hypopnea: 1).
17
+ * **Wake Trimming:** If excessive "Wake" periods exist at the beginning or end of a recording, they are trimmed to a maximum of 30 minutes.
18
+ * **Sampling Rate:** The original sampling rate is preserved during this step.
19
+ * **Note:** For KISS/KVSS, the extraction logic is stored in a dedicated sub-folder.
20
+
21
+ **Output Paths:**
22
+ * `datasets/{dataset_name}/signals_MAE/{CHN_GRP}/{CHN}`: Raw biosignals.
23
+ * `datasets/{dataset_name}/annotations`: Sleep staging labels.
24
+ * `datasets/{dataset_name}/ah_labels`: Apnea-Hypopnea labels.
25
+
26
+ ---
27
+
28
+ ## 2. Signal Refinement & Memory Mapping
29
+ ### `{dataset_name}_preprocess.py`
30
+
31
+ This script processes the `.npy` files (filtering, resampling) and saves them as memory-mapped (`.mmap`) files for efficient data loading.
32
+
33
+ ### Filtering Specifications
34
+
35
+ | Signal Type | Filtering Parameters |
36
+ | :--- | :--- |
37
+ | **EEG, EOG** | Notch: 60 Hz \| Bandpass: 0.3–40 Hz |
38
+ | **ECG** | Notch: 60 Hz \| Bandpass: 0.3–60 Hz \| Peak-based inversion correction |
39
+ | **EMG** | Notch: 60 Hz \| Highpass: 10 Hz |
40
+ | **AIRFLOW, ABD, CHEST** | Lowpass: 15 Hz |
41
+
42
+ * **Resampling:** All signals are unified to a sampling rate of **100 Hz**.
43
+ * **Metadata Generation:** A `.pickle` file is created for each biosignal to manage the global `.mmap` file. It includes:
44
+ * **Indices:** Start and end positions for each case within the combined `.mmap`.
45
+ * **Statistics:** Sum and square sum per case (used later for **Standardization**).
46
+ * **Shape:** The total dimensions of the `.mmap` file.
47
+ * **Data Splitting:** Automatically performs the **Train/Val/Test** split (Only for finetuning datasets - SHHS1 and KISS).
48
+
49
+ **Output Paths:**
50
+ * `datasets/{dataset_name}/mmap_signals_MAE_processed/{split}/{CHN_GRP}/{CHN}`: `.mmap` and `.pickle` files.
51
+ * `datasets/{dataset_name}/annotations_split/{split}`: Split sleep staging labels.
52
+ * `datasets/{dataset_name}/ah_labels_split/{split}`: Split Apnea-Hypopnea labels.
53
+
54
+ ---
55
+
56
+ ## 3. Patient Demographics
57
+ ### `get_demographics.py`
58
+
59
+ This script extracts and aggregates patient-level information into a structured format.
60
+
61
+ * **Data Points:** Collects **Sex, Age, BMI, and AHI** (Apnea-Hypopnea Index).
62
+ * **Handling Missing Values:** If a specific metric was not collected for a patient, it is ignored/skipped.
63
+ * **Output Path:** `datasets/demographics/{dataset_name}_demographics.pkl`
data/cfs_meta_data/split_data.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Create a script to split the dataset into train, validation, and test sets
2
+ # The filenames are from BASE_PATH/cfs/signals_MAE/EEG/C3-M2/*.npy
3
+ import os
4
+ import random
5
+ import numpy as np
6
+
7
+ BASE_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), 'datasets')
8
+ SEED = 42
9
+ random.seed(SEED)
10
+ np.random.seed(SEED)
11
+
12
+ def split_data(data_dir, output_dir, train_ratio=0.7, val_num=50, test_ratio=0.3):
13
+ # Get all the filenames in the data directory
14
+ all_files = []
15
+ for root, dirs, files in os.walk(data_dir):
16
+ for file in files:
17
+ if file.endswith('.npy'):
18
+ pid = file.split('.')[0] # Assuming filename format is PID_XXX.npy
19
+ all_files.append(pid)
20
+
21
+ # Shuffle the filenames
22
+ random.shuffle(all_files)
23
+
24
+ # Split the data into train, validation, and test sets
25
+ total_files = len(all_files)
26
+ train_end = int(total_files * train_ratio) - val_num
27
+ val_end = train_end + val_num
28
+
29
+ train_files = all_files[:train_end]
30
+ val_files = all_files[train_end:val_end]
31
+ test_files = all_files[val_end:]
32
+
33
+ # Save the splits to output directory
34
+ os.makedirs(output_dir, exist_ok=True)
35
+
36
+ with open(os.path.join(output_dir, 'train.txt'), 'w') as f:
37
+ for file in train_files:
38
+ f.write(file + '\n')
39
+
40
+ with open(os.path.join(output_dir, 'val.txt'), 'w') as f:
41
+ for file in val_files:
42
+ f.write(file + '\n')
43
+
44
+ with open(os.path.join(output_dir, 'test.txt'), 'w') as f:
45
+ for file in test_files:
46
+ f.write(file + '\n')
47
+
48
+ if __name__ == "__main__":
49
+ data_dir = os.path.join(BASE_PATH, 'cfs', 'signals_MAE', 'EEG', 'C3-M2')
50
+ output_dir = '.'
51
+ split_data(data_dir, output_dir)
data/cfs_meta_data/test.txt ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cfs-visit5-800900
2
+ cfs-visit5-802451
3
+ cfs-visit5-802745
4
+ cfs-visit5-802201
5
+ cfs-visit5-801900
6
+ cfs-visit5-800048
7
+ cfs-visit5-800891
8
+ cfs-visit5-800195
9
+ cfs-visit5-801220
10
+ cfs-visit5-800680
11
+ cfs-visit5-802110
12
+ cfs-visit5-802180
13
+ cfs-visit5-800412
14
+ cfs-visit5-800688
15
+ cfs-visit5-801645
16
+ cfs-visit5-801942
17
+ cfs-visit5-802065
18
+ cfs-visit5-801782
19
+ cfs-visit5-800916
20
+ cfs-visit5-800690
21
+ cfs-visit5-801677
22
+ cfs-visit5-801945
23
+ cfs-visit5-800038
24
+ cfs-visit5-800544
25
+ cfs-visit5-802104
26
+ cfs-visit5-801602
27
+ cfs-visit5-801773
28
+ cfs-visit5-801814
29
+ cfs-visit5-800375
30
+ cfs-visit5-802242
31
+ cfs-visit5-801035
32
+ cfs-visit5-800968
33
+ cfs-visit5-802385
34
+ cfs-visit5-801323
35
+ cfs-visit5-800604
36
+ cfs-visit5-801651
37
+ cfs-visit5-802380
38
+ cfs-visit5-801126
39
+ cfs-visit5-800780
40
+ cfs-visit5-800113
41
+ cfs-visit5-800170
42
+ cfs-visit5-800365
43
+ cfs-visit5-800908
44
+ cfs-visit5-801770
45
+ cfs-visit5-800705
46
+ cfs-visit5-801085
47
+ cfs-visit5-800697
48
+ cfs-visit5-802335
49
+ cfs-visit5-801337
50
+ cfs-visit5-801788
51
+ cfs-visit5-802449
52
+ cfs-visit5-802303
53
+ cfs-visit5-802228
54
+ cfs-visit5-800861
55
+ cfs-visit5-801162
56
+ cfs-visit5-800194
57
+ cfs-visit5-800985
58
+ cfs-visit5-801735
59
+ cfs-visit5-800021
60
+ cfs-visit5-800980
61
+ cfs-visit5-802482
62
+ cfs-visit5-800078
63
+ cfs-visit5-802185
64
+ cfs-visit5-802171
65
+ cfs-visit5-802691
66
+ cfs-visit5-801396
67
+ cfs-visit5-800769
68
+ cfs-visit5-801576
69
+ cfs-visit5-801794
70
+ cfs-visit5-801762
71
+ cfs-visit5-800926
72
+ cfs-visit5-801432
73
+ cfs-visit5-802038
74
+ cfs-visit5-801058
75
+ cfs-visit5-802460
76
+ cfs-visit5-800247
77
+ cfs-visit5-800271
78
+ cfs-visit5-802075
79
+ cfs-visit5-801454
80
+ cfs-visit5-802010
81
+ cfs-visit5-800226
82
+ cfs-visit5-800672
83
+ cfs-visit5-801445
84
+ cfs-visit5-800197
85
+ cfs-visit5-802533
86
+ cfs-visit5-800313
87
+ cfs-visit5-801225
88
+ cfs-visit5-802716
89
+ cfs-visit5-801299
90
+ cfs-visit5-800847
91
+ cfs-visit5-800122
92
+ cfs-visit5-802593
93
+ cfs-visit5-802573
94
+ cfs-visit5-801037
95
+ cfs-visit5-801638
96
+ cfs-visit5-801719
97
+ cfs-visit5-801246
98
+ cfs-visit5-801325
99
+ cfs-visit5-801587
100
+ cfs-visit5-801438
101
+ cfs-visit5-801291
102
+ cfs-visit5-801393
103
+ cfs-visit5-801540
104
+ cfs-visit5-800716
105
+ cfs-visit5-801152
106
+ cfs-visit5-800229
107
+ cfs-visit5-802612
108
+ cfs-visit5-800490
109
+ cfs-visit5-801311
110
+ cfs-visit5-801528
111
+ cfs-visit5-802072
112
+ cfs-visit5-801675
113
+ cfs-visit5-801101
114
+ cfs-visit5-800617
115
+ cfs-visit5-802005
116
+ cfs-visit5-801080
117
+ cfs-visit5-800203
118
+ cfs-visit5-802252
119
+ cfs-visit5-802549
120
+ cfs-visit5-801352
121
+ cfs-visit5-800665
122
+ cfs-visit5-802658
123
+ cfs-visit5-801144
124
+ cfs-visit5-800434
125
+ cfs-visit5-801902
126
+ cfs-visit5-801806
127
+ cfs-visit5-801559
128
+ cfs-visit5-800841
129
+ cfs-visit5-801150
130
+ cfs-visit5-801685
131
+ cfs-visit5-801335
132
+ cfs-visit5-800658
133
+ cfs-visit5-801159
134
+ cfs-visit5-800136
135
+ cfs-visit5-801497
136
+ cfs-visit5-800719
137
+ cfs-visit5-802724
138
+ cfs-visit5-801458
139
+ cfs-visit5-802678
140
+ cfs-visit5-800105
141
+ cfs-visit5-802475
142
+ cfs-visit5-800449
143
+ cfs-visit5-800326
144
+ cfs-visit5-801650
145
+ cfs-visit5-800380
146
+ cfs-visit5-801446
147
+ cfs-visit5-801859
148
+ cfs-visit5-800236
149
+ cfs-visit5-800953
150
+ cfs-visit5-800049
151
+ cfs-visit5-802637
152
+ cfs-visit5-800971
153
+ cfs-visit5-802487
154
+ cfs-visit5-802648
155
+ cfs-visit5-801833
156
+ cfs-visit5-800321
157
+ cfs-visit5-800494
158
+ cfs-visit5-801381
159
+ cfs-visit5-801264
160
+ cfs-visit5-800395
161
+ cfs-visit5-802717
162
+ cfs-visit5-801270
163
+ cfs-visit5-802368
164
+ cfs-visit5-801747
165
+ cfs-visit5-801166
166
+ cfs-visit5-800440
167
+ cfs-visit5-800311
168
+ cfs-visit5-802123
169
+ cfs-visit5-800811
170
+ cfs-visit5-801137
171
+ cfs-visit5-801294
172
+ cfs-visit5-800545
173
+ cfs-visit5-801095
174
+ cfs-visit5-801724
175
+ cfs-visit5-800512
176
+ cfs-visit5-802498
177
+ cfs-visit5-802125
178
+ cfs-visit5-802753
179
+ cfs-visit5-801278
180
+ cfs-visit5-801501
181
+ cfs-visit5-800594
182
+ cfs-visit5-802154
183
+ cfs-visit5-801662
184
+ cfs-visit5-800011
185
+ cfs-visit5-800905
186
+ cfs-visit5-800017
187
+ cfs-visit5-801706
188
+ cfs-visit5-800329
189
+ cfs-visit5-801855
190
+ cfs-visit5-801231
191
+ cfs-visit5-802295
192
+ cfs-visit5-801732
193
+ cfs-visit5-801019
194
+ cfs-visit5-801526
195
+ cfs-visit5-802268
196
+ cfs-visit5-801110
197
+ cfs-visit5-800211
198
+ cfs-visit5-800851
199
+ cfs-visit5-802537
200
+ cfs-visit5-800471
201
+ cfs-visit5-801809
data/cfs_meta_data/train.txt ADDED
@@ -0,0 +1,418 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cfs-visit5-800238
2
+ cfs-visit5-801487
3
+ cfs-visit5-801341
4
+ cfs-visit5-801427
5
+ cfs-visit5-802462
6
+ cfs-visit5-800733
7
+ cfs-visit5-802346
8
+ cfs-visit5-802467
9
+ cfs-visit5-800914
10
+ cfs-visit5-801181
11
+ cfs-visit5-802435
12
+ cfs-visit5-801850
13
+ cfs-visit5-800325
14
+ cfs-visit5-801660
15
+ cfs-visit5-800099
16
+ cfs-visit5-800801
17
+ cfs-visit5-800805
18
+ cfs-visit5-800854
19
+ cfs-visit5-802247
20
+ cfs-visit5-800565
21
+ cfs-visit5-802273
22
+ cfs-visit5-802398
23
+ cfs-visit5-801005
24
+ cfs-visit5-801173
25
+ cfs-visit5-800173
26
+ cfs-visit5-801267
27
+ cfs-visit5-800522
28
+ cfs-visit5-802408
29
+ cfs-visit5-802711
30
+ cfs-visit5-801928
31
+ cfs-visit5-800946
32
+ cfs-visit5-800860
33
+ cfs-visit5-801300
34
+ cfs-visit5-800220
35
+ cfs-visit5-801457
36
+ cfs-visit5-800722
37
+ cfs-visit5-802183
38
+ cfs-visit5-801350
39
+ cfs-visit5-801452
40
+ cfs-visit5-801282
41
+ cfs-visit5-800640
42
+ cfs-visit5-801800
43
+ cfs-visit5-801252
44
+ cfs-visit5-800151
45
+ cfs-visit5-801122
46
+ cfs-visit5-802233
47
+ cfs-visit5-801917
48
+ cfs-visit5-801263
49
+ cfs-visit5-802302
50
+ cfs-visit5-801312
51
+ cfs-visit5-802078
52
+ cfs-visit5-802272
53
+ cfs-visit5-801027
54
+ cfs-visit5-800316
55
+ cfs-visit5-800341
56
+ cfs-visit5-800346
57
+ cfs-visit5-800047
58
+ cfs-visit5-801734
59
+ cfs-visit5-802195
60
+ cfs-visit5-802676
61
+ cfs-visit5-801222
62
+ cfs-visit5-801052
63
+ cfs-visit5-800299
64
+ cfs-visit5-801521
65
+ cfs-visit5-802294
66
+ cfs-visit5-801183
67
+ cfs-visit5-801125
68
+ cfs-visit5-801867
69
+ cfs-visit5-800086
70
+ cfs-visit5-801346
71
+ cfs-visit5-801377
72
+ cfs-visit5-800344
73
+ cfs-visit5-801631
74
+ cfs-visit5-801416
75
+ cfs-visit5-800492
76
+ cfs-visit5-802491
77
+ cfs-visit5-800371
78
+ cfs-visit5-800109
79
+ cfs-visit5-802003
80
+ cfs-visit5-801013
81
+ cfs-visit5-800937
82
+ cfs-visit5-801449
83
+ cfs-visit5-800198
84
+ cfs-visit5-800285
85
+ cfs-visit5-801656
86
+ cfs-visit5-800427
87
+ cfs-visit5-800714
88
+ cfs-visit5-802235
89
+ cfs-visit5-800390
90
+ cfs-visit5-801488
91
+ cfs-visit5-802308
92
+ cfs-visit5-800359
93
+ cfs-visit5-800161
94
+ cfs-visit5-801609
95
+ cfs-visit5-800426
96
+ cfs-visit5-802509
97
+ cfs-visit5-800177
98
+ cfs-visit5-800939
99
+ cfs-visit5-800575
100
+ cfs-visit5-802400
101
+ cfs-visit5-801212
102
+ cfs-visit5-800506
103
+ cfs-visit5-800138
104
+ cfs-visit5-802466
105
+ cfs-visit5-800118
106
+ cfs-visit5-800973
107
+ cfs-visit5-802340
108
+ cfs-visit5-801790
109
+ cfs-visit5-801366
110
+ cfs-visit5-802366
111
+ cfs-visit5-800110
112
+ cfs-visit5-800799
113
+ cfs-visit5-802726
114
+ cfs-visit5-801139
115
+ cfs-visit5-802094
116
+ cfs-visit5-802042
117
+ cfs-visit5-800757
118
+ cfs-visit5-801453
119
+ cfs-visit5-800280
120
+ cfs-visit5-800187
121
+ cfs-visit5-800509
122
+ cfs-visit5-800576
123
+ cfs-visit5-800081
124
+ cfs-visit5-801158
125
+ cfs-visit5-801289
126
+ cfs-visit5-800216
127
+ cfs-visit5-801849
128
+ cfs-visit5-801780
129
+ cfs-visit5-802474
130
+ cfs-visit5-801530
131
+ cfs-visit5-802386
132
+ cfs-visit5-801610
133
+ cfs-visit5-800347
134
+ cfs-visit5-802182
135
+ cfs-visit5-802073
136
+ cfs-visit5-801813
137
+ cfs-visit5-802106
138
+ cfs-visit5-802500
139
+ cfs-visit5-802459
140
+ cfs-visit5-800228
141
+ cfs-visit5-801909
142
+ cfs-visit5-801199
143
+ cfs-visit5-800659
144
+ cfs-visit5-801848
145
+ cfs-visit5-801012
146
+ cfs-visit5-802529
147
+ cfs-visit5-801448
148
+ cfs-visit5-801206
149
+ cfs-visit5-800421
150
+ cfs-visit5-801474
151
+ cfs-visit5-800618
152
+ cfs-visit5-801998
153
+ cfs-visit5-801912
154
+ cfs-visit5-802211
155
+ cfs-visit5-801585
156
+ cfs-visit5-802060
157
+ cfs-visit5-801357
158
+ cfs-visit5-801792
159
+ cfs-visit5-801785
160
+ cfs-visit5-802503
161
+ cfs-visit5-801021
162
+ cfs-visit5-801355
163
+ cfs-visit5-800227
164
+ cfs-visit5-800032
165
+ cfs-visit5-801590
166
+ cfs-visit5-802731
167
+ cfs-visit5-801919
168
+ cfs-visit5-802555
169
+ cfs-visit5-802103
170
+ cfs-visit5-802205
171
+ cfs-visit5-802734
172
+ cfs-visit5-801591
173
+ cfs-visit5-800364
174
+ cfs-visit5-801319
175
+ cfs-visit5-802004
176
+ cfs-visit5-801112
177
+ cfs-visit5-801376
178
+ cfs-visit5-801825
179
+ cfs-visit5-800072
180
+ cfs-visit5-801491
181
+ cfs-visit5-802424
182
+ cfs-visit5-800159
183
+ cfs-visit5-801707
184
+ cfs-visit5-800404
185
+ cfs-visit5-800630
186
+ cfs-visit5-801038
187
+ cfs-visit5-801858
188
+ cfs-visit5-801936
189
+ cfs-visit5-801064
190
+ cfs-visit5-802109
191
+ cfs-visit5-801340
192
+ cfs-visit5-801864
193
+ cfs-visit5-801373
194
+ cfs-visit5-802659
195
+ cfs-visit5-801389
196
+ cfs-visit5-801444
197
+ cfs-visit5-800400
198
+ cfs-visit5-800911
199
+ cfs-visit5-801133
200
+ cfs-visit5-800666
201
+ cfs-visit5-802626
202
+ cfs-visit5-800505
203
+ cfs-visit5-800393
204
+ cfs-visit5-802619
205
+ cfs-visit5-801331
206
+ cfs-visit5-802427
207
+ cfs-visit5-801326
208
+ cfs-visit5-800883
209
+ cfs-visit5-801569
210
+ cfs-visit5-800148
211
+ cfs-visit5-802206
212
+ cfs-visit5-800527
213
+ cfs-visit5-801731
214
+ cfs-visit5-800928
215
+ cfs-visit5-802011
216
+ cfs-visit5-800114
217
+ cfs-visit5-802634
218
+ cfs-visit5-800949
219
+ cfs-visit5-801213
220
+ cfs-visit5-800643
221
+ cfs-visit5-800024
222
+ cfs-visit5-802218
223
+ cfs-visit5-800737
224
+ cfs-visit5-801666
225
+ cfs-visit5-801370
226
+ cfs-visit5-800962
227
+ cfs-visit5-801233
228
+ cfs-visit5-801983
229
+ cfs-visit5-802322
230
+ cfs-visit5-801421
231
+ cfs-visit5-801771
232
+ cfs-visit5-801982
233
+ cfs-visit5-802523
234
+ cfs-visit5-800917
235
+ cfs-visit5-802495
236
+ cfs-visit5-801633
237
+ cfs-visit5-800349
238
+ cfs-visit5-801380
239
+ cfs-visit5-801078
240
+ cfs-visit5-800821
241
+ cfs-visit5-800557
242
+ cfs-visit5-800551
243
+ cfs-visit5-800657
244
+ cfs-visit5-801838
245
+ cfs-visit5-800996
246
+ cfs-visit5-801461
247
+ cfs-visit5-802578
248
+ cfs-visit5-801963
249
+ cfs-visit5-801514
250
+ cfs-visit5-800461
251
+ cfs-visit5-800340
252
+ cfs-visit5-801177
253
+ cfs-visit5-800312
254
+ cfs-visit5-802718
255
+ cfs-visit5-800528
256
+ cfs-visit5-800221
257
+ cfs-visit5-802465
258
+ cfs-visit5-801916
259
+ cfs-visit5-801757
260
+ cfs-visit5-800531
261
+ cfs-visit5-801805
262
+ cfs-visit5-802300
263
+ cfs-visit5-801248
264
+ cfs-visit5-802522
265
+ cfs-visit5-802018
266
+ cfs-visit5-801517
267
+ cfs-visit5-800839
268
+ cfs-visit5-800798
269
+ cfs-visit5-802315
270
+ cfs-visit5-802257
271
+ cfs-visit5-801420
272
+ cfs-visit5-800002
273
+ cfs-visit5-801310
274
+ cfs-visit5-801243
275
+ cfs-visit5-801831
276
+ cfs-visit5-800616
277
+ cfs-visit5-800410
278
+ cfs-visit5-802421
279
+ cfs-visit5-801075
280
+ cfs-visit5-801494
281
+ cfs-visit5-802113
282
+ cfs-visit5-800129
283
+ cfs-visit5-802610
284
+ cfs-visit5-800890
285
+ cfs-visit5-801554
286
+ cfs-visit5-800411
287
+ cfs-visit5-800392
288
+ cfs-visit5-802382
289
+ cfs-visit5-800613
290
+ cfs-visit5-800693
291
+ cfs-visit5-801996
292
+ cfs-visit5-802720
293
+ cfs-visit5-800183
294
+ cfs-visit5-801502
295
+ cfs-visit5-802587
296
+ cfs-visit5-801001
297
+ cfs-visit5-800037
298
+ cfs-visit5-801933
299
+ cfs-visit5-801463
300
+ cfs-visit5-800279
301
+ cfs-visit5-802099
302
+ cfs-visit5-800923
303
+ cfs-visit5-802721
304
+ cfs-visit5-802101
305
+ cfs-visit5-802196
306
+ cfs-visit5-802132
307
+ cfs-visit5-802595
308
+ cfs-visit5-800853
309
+ cfs-visit5-800825
310
+ cfs-visit5-801196
311
+ cfs-visit5-802021
312
+ cfs-visit5-801841
313
+ cfs-visit5-801425
314
+ cfs-visit5-802144
315
+ cfs-visit5-802081
316
+ cfs-visit5-802635
317
+ cfs-visit5-802041
318
+ cfs-visit5-800363
319
+ cfs-visit5-802654
320
+ cfs-visit5-800912
321
+ cfs-visit5-800498
322
+ cfs-visit5-802438
323
+ cfs-visit5-800451
324
+ cfs-visit5-802298
325
+ cfs-visit5-800597
326
+ cfs-visit5-801307
327
+ cfs-visit5-800027
328
+ cfs-visit5-802355
329
+ cfs-visit5-801193
330
+ cfs-visit5-800104
331
+ cfs-visit5-800537
332
+ cfs-visit5-801658
333
+ cfs-visit5-802213
334
+ cfs-visit5-801966
335
+ cfs-visit5-800115
336
+ cfs-visit5-801835
337
+ cfs-visit5-800718
338
+ cfs-visit5-801668
339
+ cfs-visit5-800789
340
+ cfs-visit5-802502
341
+ cfs-visit5-800625
342
+ cfs-visit5-801147
343
+ cfs-visit5-800040
344
+ cfs-visit5-802086
345
+ cfs-visit5-802330
346
+ cfs-visit5-800356
347
+ cfs-visit5-802076
348
+ cfs-visit5-801157
349
+ cfs-visit5-802056
350
+ cfs-visit5-800249
351
+ cfs-visit5-802401
352
+ cfs-visit5-801674
353
+ cfs-visit5-802388
354
+ cfs-visit5-802739
355
+ cfs-visit5-802301
356
+ cfs-visit5-801413
357
+ cfs-visit5-802709
358
+ cfs-visit5-801034
359
+ cfs-visit5-802579
360
+ cfs-visit5-800334
361
+ cfs-visit5-800960
362
+ cfs-visit5-801811
363
+ cfs-visit5-801563
364
+ cfs-visit5-802675
365
+ cfs-visit5-800212
366
+ cfs-visit5-800385
367
+ cfs-visit5-800230
368
+ cfs-visit5-800179
369
+ cfs-visit5-802348
370
+ cfs-visit5-801224
371
+ cfs-visit5-800092
372
+ cfs-visit5-801033
373
+ cfs-visit5-800975
374
+ cfs-visit5-801387
375
+ cfs-visit5-801121
376
+ cfs-visit5-800045
377
+ cfs-visit5-800535
378
+ cfs-visit5-802219
379
+ cfs-visit5-801041
380
+ cfs-visit5-800820
381
+ cfs-visit5-801907
382
+ cfs-visit5-802627
383
+ cfs-visit5-800927
384
+ cfs-visit5-800199
385
+ cfs-visit5-800331
386
+ cfs-visit5-800232
387
+ cfs-visit5-801228
388
+ cfs-visit5-802223
389
+ cfs-visit5-800243
390
+ cfs-visit5-800176
391
+ cfs-visit5-801532
392
+ cfs-visit5-800647
393
+ cfs-visit5-800272
394
+ cfs-visit5-800990
395
+ cfs-visit5-800715
396
+ cfs-visit5-800606
397
+ cfs-visit5-802483
398
+ cfs-visit5-801414
399
+ cfs-visit5-802748
400
+ cfs-visit5-800035
401
+ cfs-visit5-801226
402
+ cfs-visit5-800501
403
+ cfs-visit5-800389
404
+ cfs-visit5-801922
405
+ cfs-visit5-800481
406
+ cfs-visit5-802176
407
+ cfs-visit5-800464
408
+ cfs-visit5-801827
409
+ cfs-visit5-801596
410
+ cfs-visit5-802645
411
+ cfs-visit5-801161
412
+ cfs-visit5-802283
413
+ cfs-visit5-801713
414
+ cfs-visit5-801873
415
+ cfs-visit5-800554
416
+ cfs-visit5-801044
417
+ cfs-visit5-802643
418
+ cfs-visit5-800276
data/cfs_meta_data/val.txt ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cfs-visit5-800202
2
+ cfs-visit5-800184
3
+ cfs-visit5-800702
4
+ cfs-visit5-800071
5
+ cfs-visit5-801071
6
+ cfs-visit5-800367
7
+ cfs-visit5-801960
8
+ cfs-visit5-801764
9
+ cfs-visit5-802304
10
+ cfs-visit5-802001
11
+ cfs-visit5-800130
12
+ cfs-visit5-801320
13
+ cfs-visit5-801689
14
+ cfs-visit5-801131
15
+ cfs-visit5-801149
16
+ cfs-visit5-800337
17
+ cfs-visit5-800246
18
+ cfs-visit5-801273
19
+ cfs-visit5-800174
20
+ cfs-visit5-802628
21
+ cfs-visit5-800474
22
+ cfs-visit5-800945
23
+ cfs-visit5-800010
24
+ cfs-visit5-800182
25
+ cfs-visit5-800667
26
+ cfs-visit5-800785
27
+ cfs-visit5-800967
28
+ cfs-visit5-800497
29
+ cfs-visit5-801077
30
+ cfs-visit5-800065
31
+ cfs-visit5-801760
32
+ cfs-visit5-802454
33
+ cfs-visit5-800355
34
+ cfs-visit5-802332
35
+ cfs-visit5-800051
36
+ cfs-visit5-801988
37
+ cfs-visit5-802471
38
+ cfs-visit5-802279
39
+ cfs-visit5-801949
40
+ cfs-visit5-801908
41
+ cfs-visit5-801553
42
+ cfs-visit5-801435
43
+ cfs-visit5-800596
44
+ cfs-visit5-802664
45
+ cfs-visit5-802177
46
+ cfs-visit5-801868
47
+ cfs-visit5-800407
48
+ cfs-visit5-800901
49
+ cfs-visit5-800577
50
+ cfs-visit5-800373
data/cfs_preprocess.py ADDED
@@ -0,0 +1,372 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+ import numpy as np
4
+ import matplotlib.pyplot as plt
5
+ from tqdm import tqdm
6
+ import shutil
7
+ import librosa
8
+
9
+ from scipy.signal import iirnotch, lfilter
10
+ from data_utils import butter_bandpass_filter, correct_ecg_inversion
11
+ import pickle
12
+ import pandas as pd
13
+
14
+ BASE_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'datasets')
15
+ NOTCH_FREQ = 60
16
+ EEG_LOWCUT = 0.3
17
+ EEG_HIGHCUT = 40
18
+ EMG_LOWCUT = 10
19
+ EMG_HIGHCUT = 1000
20
+ ECG_LOWCUT = 0.3
21
+ ECG_HIGHCUT = 60
22
+ FLOW_LOWCUT = 0
23
+ FLOW_HIGHCUT = 15
24
+
25
+ NUM_PROCESS = 4
26
+
27
+ import argparse
28
+ import multiprocessing
29
+
30
+ TARGET_RESAMPLE = 100
31
+
32
+
33
+
34
+ def process_ecg(args):
35
+ sig, chn_grp, chn = args
36
+ sig_path = os.path.join(BASE_PATH, cfg.data_dir, chn_grp, chn, sig)
37
+ data = np.load(sig_path)
38
+ sampling_rate = data.shape[1] // (30)
39
+
40
+ data = data.reshape(-1, 1)
41
+ # Apply bandpass filter
42
+ filtered = butter_bandpass_filter(data, ECG_LOWCUT, ECG_HIGHCUT, sampling_rate)
43
+ b_notch, a_notch = iirnotch(NOTCH_FREQ, 30, sampling_rate)
44
+ filtered = lfilter(b_notch, a_notch, filtered)
45
+
46
+ filtered = filtered.reshape(-1, sampling_rate*30)
47
+ # filtered = librosa.resample(filtered, orig_sr=SAMPLING_RATE, target_sr=TARGET_RESAMPLE, axis=0, res_type='soxr_qq')
48
+
49
+ filtered_epochs = []
50
+
51
+ for epoch in filtered:
52
+ inv_epoch, _ = correct_ecg_inversion(epoch, TARGET_RESAMPLE)
53
+ filtered_epochs.append(inv_epoch)
54
+
55
+ filtered = np.stack(filtered_epochs, axis=0)
56
+
57
+ if sampling_rate != TARGET_RESAMPLE:
58
+ filtered = np.reshape(filtered, (-1,1))
59
+ filtered = librosa.resample(filtered, orig_sr=sampling_rate, target_sr=TARGET_RESAMPLE, axis=0, res_type='soxr_qq')
60
+ filtered = filtered.reshape(-1, TARGET_RESAMPLE*30)
61
+
62
+ if cfg.save_type == 'npy':
63
+ # Save processed data
64
+ output_path = os.path.join(BASE_PATH, cfg.output_dir, chn_grp, chn, sig)
65
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
66
+ np.save(output_path, filtered.astype(np.float32))
67
+ return
68
+ else:
69
+ return filtered
70
+
71
+
72
+ def process_eeg(args):
73
+ sig, chn_grp, chn = args
74
+ sig_path = os.path.join(BASE_PATH, cfg.data_dir, chn_grp, chn, sig)
75
+ data = np.load(sig_path)
76
+ sampling_rate = data.shape[1] // (30)
77
+ data = data.reshape(-1, 1)
78
+ # Apply bandpass filter
79
+ filtered = butter_bandpass_filter(data, EEG_LOWCUT, EEG_HIGHCUT, sampling_rate)
80
+ b_notch, a_notch = iirnotch(NOTCH_FREQ, 30, sampling_rate)
81
+ filtered = lfilter(b_notch, a_notch, filtered)
82
+ if sampling_rate != TARGET_RESAMPLE:
83
+ filtered = librosa.resample(filtered, orig_sr=sampling_rate, target_sr=TARGET_RESAMPLE, axis=0, res_type='soxr_qq')
84
+ filtered = filtered.reshape(-1, TARGET_RESAMPLE*30)
85
+
86
+ if cfg.save_type == 'npy':
87
+ # Save processed data
88
+ output_path = os.path.join(BASE_PATH, cfg.output_dir, chn_grp, chn, sig)
89
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
90
+ np.save(output_path, filtered.astype(np.float32))
91
+ return
92
+ else:
93
+ return filtered
94
+
95
+ def process_emg(args):
96
+ sig, chn_grp, chn = args
97
+ sig_path = os.path.join(BASE_PATH, cfg.data_dir, chn_grp, chn, sig)
98
+ data = np.load(sig_path)
99
+ sampling_rate = data.shape[1] // (30)
100
+ data = data.reshape(-1, 1)
101
+ # Apply bandpass filter
102
+ filtered = butter_bandpass_filter(data, EMG_LOWCUT, EMG_HIGHCUT, sampling_rate)
103
+ b_notch, a_notch = iirnotch(NOTCH_FREQ, 30, sampling_rate)
104
+ filtered = lfilter(b_notch, a_notch, filtered)
105
+ if sampling_rate != TARGET_RESAMPLE:
106
+ filtered = librosa.resample(filtered, orig_sr=sampling_rate, target_sr=TARGET_RESAMPLE, axis=0, res_type='soxr_qq')
107
+ filtered = filtered.reshape(-1, TARGET_RESAMPLE*30)
108
+
109
+ if cfg.save_type == 'npy':
110
+ # Save processed data
111
+ output_path = os.path.join(BASE_PATH, cfg.output_dir, chn_grp, chn, sig)
112
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
113
+ np.save(output_path, filtered.astype(np.float32))
114
+ return
115
+ else:
116
+ return filtered
117
+
118
+ def process_flow(args):
119
+ sig, chn_grp, chn = args
120
+ sig_path = os.path.join(BASE_PATH, cfg.data_dir, chn_grp, chn, sig)
121
+ data = np.load(sig_path)
122
+ sampling_rate = data.shape[1] // (30)
123
+ data = data.reshape(-1, 1)
124
+ # Apply bandpass filter
125
+ filtered = butter_bandpass_filter(data, FLOW_LOWCUT, FLOW_HIGHCUT, sampling_rate)
126
+ if sampling_rate != TARGET_RESAMPLE:
127
+ filtered = librosa.resample(filtered, orig_sr=sampling_rate, target_sr=TARGET_RESAMPLE, axis=0, res_type='soxr_qq')
128
+
129
+ # median filter?
130
+
131
+ filtered = filtered.reshape(-1, TARGET_RESAMPLE*30)
132
+
133
+ if cfg.save_type == 'npy':
134
+ # Save processed data
135
+ output_path = os.path.join(BASE_PATH, cfg.output_dir, chn_grp, chn, sig)
136
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
137
+ np.save(output_path, filtered.astype(np.float32))
138
+ return
139
+ else:
140
+ return filtered
141
+
142
+ def save_mmap(results, sig_list, chn_grp, chn, split='train'):
143
+ signame_list = [sig.split('.')[0] for sig in sig_list]
144
+ epoch_lengths = [sig.shape[0] for sig in results]
145
+ metadata = dict()
146
+ sig_info = dict()
147
+ start, end = 0, 0
148
+ for signame, sig in zip(signame_list, results):
149
+ length = sig.shape[0]
150
+ end = start + length
151
+ info = dict()
152
+ info['pos'] = (start, end)
153
+ info['stats'] = {'sum': float(np.sum(sig)), 'sumsq': float(np.sum(sig ** 2))}
154
+ sig_info[signame] = info
155
+ start = end
156
+
157
+
158
+ mmap_path = os.path.join(BASE_PATH, cfg.output_dir, split, chn_grp, f'{chn}.mmap')
159
+ signals_cat = np.concatenate(results, axis=0).astype(np.float32)
160
+ os.makedirs(os.path.dirname(mmap_path), exist_ok=True)
161
+ data = np.memmap(mmap_path, dtype=np.float32, mode='w+', shape=signals_cat.shape)
162
+ data[:] = signals_cat
163
+ data.flush()
164
+
165
+ metadata['sig_info'] = sig_info
166
+ metadata['data_shape'] = signals_cat.shape
167
+ info_path = os.path.join(BASE_PATH, cfg.output_dir, split, chn_grp, f'{chn}.pickle')
168
+ with open(info_path, 'wb') as f:
169
+ pickle.dump(metadata, f)
170
+
171
+
172
+ def preprocess(sig_list, chn_grp=None, chn=None, split='train'):
173
+ def _process(sig_list, chn_grp, chn, split):
174
+
175
+ print(f"Processing {chn_grp}/{chn}")
176
+ # if not (chn == "C4-A1" or chn == "AIRFLOW"): continue
177
+
178
+ if chn_grp in ['EEG','EOG']:
179
+ # sig_list = sorted(os.listdir(os.path.join(BASE_PATH, cfg.data_dir, chn_grp, chn)))
180
+ input_list = [(sig, chn_grp, chn) for sig in sig_list]
181
+ with multiprocessing.Pool(NUM_PROCESS) as pool:
182
+ results = list(tqdm(pool.imap(process_eeg, input_list), total=len(input_list)))
183
+ if cfg.save_type == 'mmap':
184
+ save_mmap(results, sig_list, chn_grp, chn, split)
185
+
186
+ elif chn_grp in ['EMG']:
187
+ # sig_list = os.listdir(os.path.join(BASE_PATH, cfg.data_dir, chn_grp, chn))
188
+ input_list = [(sig, chn_grp, chn) for sig in sig_list]
189
+ with multiprocessing.Pool(NUM_PROCESS) as pool:
190
+ results = list(tqdm(pool.imap(process_emg, input_list), total=len(input_list)))
191
+ if cfg.save_type == 'mmap':
192
+ save_mmap(results, sig_list, chn_grp, chn, split)
193
+
194
+ elif chn_grp in ['ECG']:
195
+
196
+ # sig_list = os.listdir(os.path.join(BASE_PATH, cfg.data_dir, chn_grp, chn))
197
+ input_list = [(sig, chn_grp, chn) for sig in sig_list]
198
+ with multiprocessing.Pool(NUM_PROCESS) as pool:
199
+ results = list(tqdm(pool.imap(process_ecg, input_list), total=len(input_list)))
200
+ if cfg.save_type == 'mmap':
201
+ save_mmap(results, sig_list, chn_grp, chn, split)
202
+
203
+ elif chn_grp in ['ABD', 'CHEST', 'AIRFLOW']:
204
+ # sig_list = os.listdir(os.path.join(BASE_PATH, cfg.data_dir, chn_grp, chn))
205
+ input_list = [(sig, chn_grp, chn) for sig in sig_list]
206
+ with multiprocessing.Pool(NUM_PROCESS) as pool:
207
+ results = list(tqdm(pool.imap(process_flow, input_list), total=len(input_list)))
208
+ if cfg.save_type == 'mmap':
209
+ save_mmap(results, sig_list, chn_grp, chn, split)
210
+
211
+
212
+ else:
213
+ results = []
214
+ # for sig in tqdm(sorted(os.listdir(os.path.join(BASE_PATH, cfg.data_dir, chn_grp, chn)))):
215
+ for sig in tqdm(sig_list):
216
+ sig_path = os.path.join(BASE_PATH, cfg.data_dir, chn_grp, chn, sig)
217
+ data = np.load(sig_path)
218
+ sampling_rate = data.shape[1] // (30)
219
+ if sampling_rate != TARGET_RESAMPLE or chn == 'SaO2':
220
+ # assuming 30s epochs
221
+ data = data.reshape(-1, 1)
222
+ if chn == 'SaO2':
223
+ data = librosa.resample(data, orig_sr=sampling_rate, target_sr=1, axis=0, res_type='soxr_qq')
224
+ print(np.min(data), np.max(data))
225
+ data = data / 1e8 # data range 0 to 1e8
226
+ if np.max(data) > 1 or np.min(data) < 0:
227
+ print(f"Warning: SaO2 values out of range: {sig} with min {np.min(data)} and max {np.max(data)}")
228
+ data = data.reshape(-1, 1*30)
229
+ else:
230
+ data = librosa.resample(data, orig_sr=sampling_rate, target_sr=TARGET_RESAMPLE, axis=0, res_type='soxr_qq')
231
+ data = data.reshape(-1, TARGET_RESAMPLE*30)
232
+
233
+ if cfg.save_type == 'npy':
234
+ # Save processed data
235
+ output_path = os.path.join(BASE_PATH, cfg.output_dir, chn_grp, chn, sig)
236
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
237
+ np.save(output_path, data)
238
+ elif cfg.save_type == 'mmap':
239
+ results.append(data)
240
+
241
+ save_mmap(results, sig_list, chn_grp, chn, split)
242
+
243
+
244
+ if chn_grp is not None and chn is not None:
245
+ _process(sig_list, chn_grp, chn, split)
246
+ return
247
+ else:
248
+ for chn_grp in os.listdir(os.path.join(BASE_PATH, cfg.data_dir)):
249
+ if not os.path.isdir(os.path.join(BASE_PATH, cfg.data_dir, chn_grp)):
250
+ continue
251
+ for chn in os.listdir(os.path.join(BASE_PATH, cfg.data_dir, chn_grp)):
252
+ if not os.path.isdir(os.path.join(BASE_PATH, cfg.data_dir, chn_grp, chn)):
253
+ continue
254
+ _process(sig_list, chn_grp, chn, split)
255
+
256
+
257
+ parser = argparse.ArgumentParser()
258
+ parser.add_argument('--data_dir', default='cfs/signals_MAE', help='SHHS raw data location')
259
+ parser.add_argument('--output_dir', default='cfs/mmap_signals_MAE_processed', help='SHHS processed data location')
260
+ parser.add_argument('--ann_split', action='store_true', help='To split annotation files into train/val/test')
261
+ parser.add_argument('--save_type', default='mmap', help='Which data type to save. "npy" or "mmap"')
262
+ parser.add_argument('--chn_grp', default=None, help='If specified, only preprocess this channel group')
263
+ parser.add_argument('--chn', default=None, help='If specified, only preprocess this channel')
264
+ parser.add_argument('--num_train', type=int, default=50, help='Number of training samples')
265
+
266
+ cfg = parser.parse_args()
267
+
268
+ if __name__ == '__main__':
269
+
270
+ skip_val, skip_test = False, False
271
+ if cfg.num_train <= 100:
272
+ if os.path.exists(os.path.join(BASE_PATH, cfg.output_dir, 'val')):
273
+ skip_val = True
274
+ if os.path.exists(os.path.join(BASE_PATH, cfg.output_dir, 'test')):
275
+ skip_test = True
276
+ cfg.output_dir += f"_train{cfg.num_train}"
277
+
278
+
279
+ def get_cfs_lists(cfs_split_file):
280
+ ids = pd.read_csv(os.path.join("cfs_meta_data", cfs_split_file), header=None, names=['a'])
281
+ ids = ids['a'].values.tolist()
282
+ return [id + ".npy" for id in ids]
283
+
284
+ list_files_train = get_cfs_lists("train.txt")
285
+ list_files_val = get_cfs_lists("val.txt")
286
+ list_files_test = get_cfs_lists("test.txt")
287
+
288
+ sig_list = sorted(os.listdir(os.path.join(BASE_PATH, cfg.data_dir, "EEG", "C3-M2")))
289
+
290
+ list_files_train = sorted(list(set(list_files_train).intersection(set(sig_list))))
291
+ list_files_val = list(set(list_files_val).intersection(set(sig_list)))
292
+ list_files_test = list(set(list_files_test).intersection(set(sig_list)))
293
+
294
+ if cfg.num_train <= 100:
295
+ list_files_train = list_files_train[:cfg.num_train]
296
+
297
+ print("Number of records in training set:", len(list_files_train))
298
+ print("Number of records in validation set:", len(list_files_val))
299
+ print("Number of records in test set:", len(list_files_test))
300
+
301
+ print("Processing training set...")
302
+ preprocess(list_files_train, cfg.chn_grp, cfg.chn, split='train')
303
+
304
+ if skip_val:
305
+ val_output_dir = cfg.output_dir
306
+ val_output_dir = val_output_dir.replace(f"_train{cfg.num_train}","")
307
+ os.symlink(os.path.join(BASE_PATH, val_output_dir, 'val'), os.path.join(BASE_PATH, cfg.output_dir, 'val'))
308
+ else:
309
+ print("Processing evaluation set...")
310
+ preprocess(list_files_val, cfg.chn_grp, cfg.chn, split='val')
311
+
312
+ if skip_test:
313
+ test_output_dir = cfg.output_dir
314
+ test_output_dir = test_output_dir.replace(f"_train{cfg.num_train}","")
315
+ os.symlink(os.path.join(BASE_PATH, test_output_dir, 'test'), os.path.join(BASE_PATH, cfg.output_dir, 'test'))
316
+ else:
317
+ print("Processing test set...")
318
+ preprocess(list_files_test, cfg.chn_grp, cfg.chn, split='test')
319
+
320
+
321
+ # Reorganize annotations files
322
+ # ANN_PATH = os.path.join(BASE_PATH, 'shhs1/annotations')
323
+ if cfg.ann_split:
324
+ ANN_PATH = os.path.join(os.path.dirname(os.path.join(BASE_PATH, cfg.data_dir)), 'annotations')
325
+ NEW_ANN_PATH = ANN_PATH.replace('annotations', 'annotations_split')
326
+ os.makedirs(NEW_ANN_PATH, exist_ok=True)
327
+ os.makedirs(os.path.join(NEW_ANN_PATH,'train'), exist_ok=True)
328
+ os.makedirs(os.path.join(NEW_ANN_PATH,'val'), exist_ok=True)
329
+ os.makedirs(os.path.join(NEW_ANN_PATH,'test'), exist_ok=True)
330
+
331
+ for fname in tqdm(list_files_train):
332
+ ann_fname = fname.replace('.npy', '_ann.npy')
333
+ shutil.copy(os.path.join(ANN_PATH, ann_fname), os.path.join(NEW_ANN_PATH, 'train', ann_fname))
334
+ for fname in tqdm(list_files_val):
335
+ ann_fname = fname.replace('.npy', '_ann.npy')
336
+ shutil.copy(os.path.join(ANN_PATH, ann_fname), os.path.join(NEW_ANN_PATH, 'val', ann_fname))
337
+ for fname in tqdm(list_files_test):
338
+ ann_fname = fname.replace('.npy', '_ann.npy')
339
+ shutil.copy(os.path.join(ANN_PATH, ann_fname), os.path.join(NEW_ANN_PATH, 'test', ann_fname))
340
+
341
+ AH_PATH = os.path.join(os.path.dirname(os.path.join(BASE_PATH, cfg.data_dir)), 'ah_labels')
342
+ NEW_AH_PATH = AH_PATH.replace('ah_labels', 'ah_labels_split')
343
+ os.makedirs(NEW_AH_PATH, exist_ok=True)
344
+ os.makedirs(os.path.join(NEW_AH_PATH,'train'), exist_ok=True)
345
+ os.makedirs(os.path.join(NEW_AH_PATH,'val'), exist_ok=True)
346
+ os.makedirs(os.path.join(NEW_AH_PATH,'test'), exist_ok=True)
347
+ for fname in tqdm(list_files_train):
348
+ ann_fname = fname.replace('.npy', '_ah.npy')
349
+ shutil.copy(os.path.join(AH_PATH, ann_fname), os.path.join(NEW_AH_PATH, 'train', ann_fname))
350
+ for fname in tqdm(list_files_val):
351
+ ann_fname = fname.replace('.npy', '_ah.npy')
352
+ shutil.copy(os.path.join(AH_PATH, ann_fname), os.path.join(NEW_AH_PATH, 'val', ann_fname))
353
+ for fname in tqdm(list_files_test):
354
+ ann_fname = fname.replace('.npy', '_ah.npy')
355
+ shutil.copy(os.path.join(AH_PATH, ann_fname), os.path.join(NEW_AH_PATH, 'test', ann_fname))
356
+
357
+
358
+ for split in ['train', 'val', 'test']:
359
+ # create link files to respiratory channels
360
+ os.makedirs(os.path.join(BASE_PATH, cfg.output_dir, split, 'RESP'), exist_ok=True)
361
+ for chn_grp in ['ABD', 'CHEST', 'AIRFLOW']:
362
+ chns = [f.split('.')[0] for f in os.listdir(os.path.join(BASE_PATH, cfg.output_dir, split, chn_grp))]
363
+ for chn in chns:
364
+ src_mmap = os.path.join(BASE_PATH, cfg.output_dir, split, chn_grp, f'{chn}.mmap')
365
+ src_pickle = os.path.join(BASE_PATH, cfg.output_dir, split, chn_grp, f'{chn}.pickle')
366
+ dst_mmap = os.path.join(BASE_PATH, cfg.output_dir, split, 'RESP', f'{chn}.mmap')
367
+ dst_pickle = os.path.join(BASE_PATH, cfg.output_dir, split, 'RESP', f'{chn}.pickle')
368
+ if not os.path.exists(dst_mmap):
369
+ os.symlink(src_mmap, dst_mmap)
370
+ if not os.path.exists(dst_pickle):
371
+ os.symlink(src_pickle, dst_pickle)
372
+
data/cfs_process_rawdata.py ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import scipy
3
+ import numpy as np
4
+ #!pip install wfdb
5
+ import pandas as pd
6
+ from mne.io import concatenate_raws, read_raw_edf
7
+ import xml.etree.ElementTree as ET
8
+ import multiprocessing
9
+
10
+ BASE_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'datasets')
11
+ # BASE_PATH = 'datasets'
12
+ EPOCH_SEC_SIZE = 30
13
+
14
+ # AIRFLOW_NAMES = ["NEW AIR", "NEWAIR", "AIRFLOW", "AIRFLOW-0", "airflow", "new A/F", "New Air", "AUX"]
15
+ # EEG2_NAMES = ["EEG2", "EEG 2", "EEG(sec)", "EEG sec", "EEG(SEC)"]
16
+ SELECT_CHNS = ['SaO2', 'SpO2','ECG1', 'EMG1', 'LOC', 'ROC', 'C3', 'C4', 'M1', 'M2', 'A1','A2', 'ABDO EFFORT', 'THOR EFFORT', 'AIRFLOW']
17
+ CHN_SAVE_DICT = {
18
+ 'SaO2': ('SaO2','SaO2'),
19
+ 'SpO2': ('SaO2','SaO2'),
20
+ 'ECG1': ('ECG', 'ECG'),
21
+ 'EMG1': ('EMG', 'EMG'),
22
+ 'LOC': ('EOG', 'EOG-Diff'),
23
+ 'ROC': ('EOG', 'EOG-Diff'),
24
+ 'C3': ('EEG', 'C3-M2'),
25
+ 'C4': ('EEG', 'C4-M1'),
26
+ 'M1': ('EEG', 'C4-M1'),
27
+ 'M2': ('EEG', 'C3-M2'),
28
+ 'A1': ('EEG', 'A1-M2'),
29
+ 'A2': ('EEG', 'A2-M1'),
30
+ 'ABDO EFFORT': ('ABD', 'ABD'),
31
+ 'THOR EFFORT': ('CHEST', 'CHEST'),
32
+ 'AIRFLOW': ('AIRFLOW', 'AIRFLOW')
33
+ }
34
+
35
+
36
+
37
+ import argparse
38
+ parser = argparse.ArgumentParser()
39
+ parser.add_argument('--data_dir', default="CFS_raw/polysomnography/edfs", help='CFS raw data location')
40
+ parser.add_argument('--output_dir', default='cfs/signals_MAE', help='CFS processed data location')
41
+ parser.add_argument('--annotation_dir', default='CFS_raw/polysomnography/annotations-events-profusion', help='CFS annotations location')
42
+ parser.add_argument('--ah_dir', default='CFS_raw/polysomnography/annotations-events-nsrr', help='CFS apnea/hypopnea labels location')
43
+ parser.add_argument('--demographics_file', default='CFS_raw/datasets/cfs-visit5-harmonized-dataset-0.7.0.csv', help='CFS demographics file location')
44
+
45
+ cfg = parser.parse_args()
46
+
47
+ from tqdm.auto import tqdm
48
+
49
+ def process_signal(raw, select_idx, chns, fname):
50
+ # sampling rate from instance
51
+ raw_sampling_rate = int(raw.info['sfreq'])
52
+ raw_df = raw.to_data_frame()
53
+ # print(raw_df.head())
54
+ print(raw_df.columns)
55
+ for chn in chns:
56
+ if chn == "LOC":
57
+ raw_df['EOG-Diff'] = raw_df['LOC'] - raw_df['ROC']
58
+ raw_ch_df = raw_df['EOG-Diff']
59
+ elif chn == "ROC":
60
+ continue
61
+ elif chn == 'C3':
62
+ if 'M2' in raw_df.columns:
63
+ raw_df['C3-M2'] = raw_df['C3'] - raw_df['M2']
64
+ else:
65
+ raw_df['C3-M2'] = raw_df['C3'] - raw_df['A2']
66
+ raw_ch_df = raw_df['C3-M2']
67
+ elif chn == 'C4':
68
+ if 'M1' in raw_df.columns:
69
+ raw_df['C4-M1'] = raw_df['C4'] - raw_df['M1']
70
+ else:
71
+ raw_df['C4-M1'] = raw_df['C4'] - raw_df['A1']
72
+ raw_ch_df = raw_df['C4-M1']
73
+ elif chn in ['M1', 'M2', 'A1', 'A2']:
74
+ continue
75
+ elif chn in ['SaO2', 'SpO2']:
76
+ if 'SaO2' in raw_df.columns:
77
+ raw_ch_df = raw_df['SaO2']
78
+ else:
79
+ raw_ch_df = raw_df['SpO2']
80
+ else:
81
+ raw_ch_df = raw_df[chn]
82
+ raw_ch_df = raw_ch_df.to_frame()
83
+ raw_ch_df.set_index(np.arange(len(raw_ch_df)))
84
+
85
+ # Remove movement and unknown stages if any
86
+ raw_ch = raw_ch_df.values
87
+
88
+ # Verify that we can split into 30-s epochs
89
+ if len(raw_ch) % (EPOCH_SEC_SIZE * raw_sampling_rate) != 0:
90
+ print(f"Length of raw channel ({len(raw_ch)}) \
91
+ is not multiple of raw sampling rate and epoch size ({EPOCH_SEC_SIZE} * {raw_sampling_rate})")
92
+ return np.array([])
93
+
94
+ # get (# of epochs) = (# of datapoints) / (30sec * 100Hz)
95
+ n_epochs = len(raw_ch) / (EPOCH_SEC_SIZE * raw_sampling_rate)
96
+
97
+ # Get epochs and their corresponding labels
98
+ x = np.asarray(np.split(raw_ch, n_epochs)).astype(np.float32) # split epochs
99
+
100
+ x = x[select_idx]
101
+ x = x.reshape((-1, EPOCH_SEC_SIZE * raw_sampling_rate))
102
+
103
+ chn_grp, chn_rename = CHN_SAVE_DICT[chn]
104
+ # chn_grp = CHN_SAVE_DICT[chn][0] if chn not in AIRFLOW_NAMES else 'AIRFLOW'
105
+ # chn_rename = CHN_SAVE_DICT[chn][1] if chn not in AIRFLOW_NAMES else 'AIRFLOW'
106
+ # print(chn_grp, chn_rename)
107
+ os.makedirs(os.path.join(BASE_PATH, cfg.output_dir, chn_grp, chn_rename), exist_ok=True)
108
+ np.save(os.path.join(BASE_PATH, cfg.output_dir, chn_grp, chn_rename, f"{fname}.npy"), x)
109
+
110
+ def process_data(args):
111
+
112
+ ann_fname, ah_fname, edf_fname, file_id = args
113
+ print(args)
114
+
115
+ ann_filename = os.path.basename(edf_fname).replace(".edf", "_ann.npy")
116
+ # if os.path.exists(os.path.join(BASE_PATH, cfg.output_dir, "annotations", ann_filename)):
117
+ # return
118
+
119
+ labels = []
120
+
121
+ # Read annotation and its header
122
+ t = ET.parse(ann_fname)
123
+
124
+ r = t.getroot()
125
+ faulty_File = 0
126
+
127
+ for i in range(len(r[4])):
128
+ lbl = int(r[4][i].text)
129
+ # print(lbl)
130
+ if lbl == 4: # make stages N3, N4 same as N3
131
+ labels.append(3)
132
+ elif lbl == 5: # Assign label 4 for REM stage
133
+ labels.append(4)
134
+ else:
135
+ labels.append(lbl)
136
+ if lbl > 5: # some files may contain labels > 5 BUT not the selected ones.
137
+ faulty_File = 1
138
+
139
+ if faulty_File == 1:
140
+ print("Faulty labels found!!")
141
+ return -1
142
+
143
+ labels = np.asarray(labels) # label list to npaprray
144
+
145
+ # corresponding labels
146
+ y = labels.astype(np.int32)
147
+
148
+ # Select on sleep periods
149
+ w_edge_mins = 30
150
+ # get index of first not WAKE
151
+ nw_idx = np.where(y != 0)[0]
152
+ # start from 30min before first WAKE
153
+ start_idx = nw_idx[0] - (w_edge_mins * 2)
154
+ # end at 30min after first WAKE
155
+ end_idx = nw_idx[-1] + (w_edge_mins * 2)
156
+ if start_idx < 0:
157
+ start_idx = 0
158
+ if end_idx >= len(y):
159
+ end_idx = len(y) - 1
160
+
161
+ select_idx = np.arange(start_idx, end_idx + 1)
162
+
163
+ # only selected labels
164
+ y = y[select_idx]
165
+
166
+ # get RawEDF instance
167
+ # !!!!!!!!!!!!!!!!!! 12~13 sec
168
+ raw = read_raw_edf(edf_fname, preload=True, stim_channel=None, verbose=None)
169
+ process_signal(raw, select_idx, SELECT_CHNS, os.path.basename(edf_fname).split('.')[0])
170
+
171
+ ann_dir = os.path.join(BASE_PATH, 'cfs', 'annotations')
172
+ os.makedirs(ann_dir, exist_ok=True)
173
+ np.save(os.path.join(ann_dir, ann_filename), arr=y)
174
+
175
+ tree = ET.parse(ah_fname)
176
+ root = tree.getroot()
177
+ events = root.findall('.//ScoredEvent')
178
+
179
+ total_seconds = 0
180
+
181
+ for event in events:
182
+ if event.find('EventConcept').text == 'Recording Start Time':
183
+ duration = float(event.find('Duration').text)
184
+ total_seconds = int(np.ceil(duration))
185
+ break
186
+
187
+ # 만약 Recording Start Time을 못 찾았을 경우 (예외 처리), 기존 방식대로 마지막 이벤트 시간으로 계산
188
+ if total_seconds == 0:
189
+ print("예외처리로 인한 Start time ~ End time 계산")
190
+ max_time = 0
191
+ for event in events:
192
+ try:
193
+ start = float(event.find('Start').text)
194
+ dur = float(event.find('Duration').text)
195
+ if start + dur > max_time:
196
+ max_time = start + dur
197
+ except:
198
+ continue
199
+ total_seconds = int(np.ceil(max_time))
200
+
201
+ # 2. 라벨 어레이 생성
202
+ ah_labels = np.zeros(total_seconds, dtype=int)
203
+
204
+
205
+ # 3. 호흡 이벤트 파싱 및 라벨링
206
+ for event in events:
207
+ try:
208
+ event_type = event.find('EventType').text
209
+
210
+ if event_type != 'Respiratory|Respiratory': continue # 호흡 이벤트가 아니면 스킵
211
+
212
+ concept = event.find('EventConcept').text
213
+ start = float(event.find('Start').text)
214
+ duration = float(event.find('Duration').text)
215
+
216
+ start_idx = int(round(start))
217
+ end_idx = start_idx + int(round(duration))
218
+
219
+ # 인덱스 범위 보정
220
+ if end_idx > total_seconds:
221
+ end_idx = total_seconds
222
+
223
+ # 라벨링 (Hypopnea=1, Apnea=2)
224
+ if 'Hypopnea' in concept:
225
+ mask = ah_labels[start_idx:end_idx] != 2
226
+ ah_labels[start_idx:end_idx][mask] = 1
227
+
228
+ elif any(x in concept for x in ['Obstructive', 'Central', 'Mixed']):
229
+ ah_labels[start_idx:end_idx] = 2
230
+
231
+ except AttributeError:
232
+ continue
233
+
234
+ ah_labels = np.reshape(ah_labels, (-1, 30))
235
+ ah_labels = ah_labels[select_idx]
236
+ assert len(ah_labels) == len(y), f"Length of ah_labels ({len(ah_labels)}) does not match length of sleep stage labels ({len(y)})"
237
+
238
+ ah_labels = np.reshape(ah_labels, (-1,))
239
+
240
+ ah_dir = os.path.join(BASE_PATH, 'cfs', 'ah_labels')
241
+ ah_filename = os.path.basename(edf_fname).replace(".edf", "_ah.npy")
242
+ os.makedirs(ah_dir, exist_ok=True)
243
+ np.save(os.path.join(ah_dir, ah_filename), arr=ah_labels)
244
+
245
+
246
+ if __name__ == '__main__':
247
+
248
+ # data_dir = '/tf/00_data/kdpark/physionet_2018/physionet_rawdata'
249
+ file_list = os.listdir(os.path.join(BASE_PATH, cfg.data_dir))
250
+
251
+ demo = pd.read_csv(os.path.join(BASE_PATH, cfg.demographics_file))
252
+ def get_nsrrid(filename):
253
+ nsrrid = filename.split('-')[-1].replace('.edf', '')
254
+ return int(nsrrid)
255
+
256
+ age_filtered_df = demo[demo['nsrr_age'] > 13]
257
+
258
+ file_list = [filename for filename in file_list if get_nsrrid(filename) in age_filtered_df['nsrrid'].values]
259
+ print(f"Number of files after filtering by age > 13: {len(file_list)}")
260
+
261
+ filenames_edf = [filename for filename in file_list if filename.endswith('.edf')]
262
+ filenames_ann = [filename.replace('.edf', '-profusion.xml') for filename in filenames_edf]
263
+ filenames_ah = [filename.replace('.edf', '-nsrr.xml') for filename in filenames_edf]
264
+
265
+
266
+ edf_fnames = [os.path.join(BASE_PATH, cfg.data_dir, filename_edf) for filename_edf in filenames_edf]
267
+ ann_fnames = [os.path.join(BASE_PATH, cfg.annotation_dir, filename_ann) for filename_ann in filenames_ann]
268
+ ah_fnames = [os.path.join(BASE_PATH, cfg.ah_dir, filename_ah) for filename_ah in filenames_ah]
269
+
270
+ edf_fnames.sort() # sort edf file names list
271
+ ann_fnames.sort() # sort ann file names list
272
+ ah_fnames.sort() # sort ah file names list
273
+
274
+ input_list = zip(ann_fnames, ah_fnames, edf_fnames, range(len(ann_fnames)))
275
+
276
+
277
+ # redo_list = ['shhs1-203353.npy', 'shhs1-203171.npy', 'shhs1-203301.npy', 'shhs1-203011.npy', 'shhs1-203300.npy', 'shhs1-203419.npy', 'shhs1-203286.npy', 'shhs1-203375.npy','shhs1-201820.npy']
278
+ # input_list = [args for args in input_list if os.path.basename(args[1]).replace('.edf', '.npy') in redo_list]
279
+ # print(len(input_list))
280
+ # exit(0)
281
+
282
+ # for args in input_list:
283
+ # ann_fname, edf_fname, file_id = args
284
+ # if 'shhs1-201820' in edf_fname:
285
+ # process_data(args)
286
+ # break
287
+
288
+ with multiprocessing.Pool(8) as pool:
289
+ list(tqdm(pool.imap(process_data, input_list), total=len(ann_fnames)))
290
+
291
+
data/data_augments.py ADDED
@@ -0,0 +1,318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import random
3
+ import numpy as np
4
+ import torch.nn.functional as F
5
+ """
6
+ Functions for Video Data augmentation.
7
+ Transforms are applied to the tensor frames of shape (frames_per_slide, height, width).
8
+ """
9
+ class TensorRandomFlip:
10
+ """Randomly flips the tensor horizontally or vertically."""
11
+ def __init__(self, horizontal=True, vertical=False, p=0.5):
12
+ self.horizontal = horizontal
13
+ self.vertical = vertical
14
+ self.p = p
15
+
16
+ def __call__(self, frames):
17
+ # Get 2 random numbers for horizontal and vertical flips
18
+ rands = np.random.rand(2)
19
+ if rands[0] < self.p and self.horizontal:
20
+ frames = torch.flip(frames, dims=[2])
21
+ if rands[1] < self.p and self.vertical:
22
+ frames = torch.flip(frames, dims=[1])
23
+ return frames
24
+
25
+
26
+ class TensorNormalize01:
27
+ """Normalizes the tensor into 0 and 1"""
28
+ def __init__(self):
29
+ pass
30
+
31
+ def __call__(self, frames):
32
+ return frames / 255.0
33
+
34
+
35
+ class TensorNormalize:
36
+ """Normalizes the tensor with the given mean and std.
37
+ Mean and std not calculated yet.
38
+ """
39
+ def __init__(self, mean=0.5, std=0.5):
40
+ self.mean = mean
41
+ self.std = std
42
+
43
+ def __call__(self, frames):
44
+ # return (frames/255.0 - self.mean) / self.std
45
+ for i in range(len(frames.shape) - 1):
46
+ m = torch.tensor(self.mean, dtype=torch.float32).unsqueeze(0)
47
+ s = torch.tensor(self.std, dtype=torch.float32).unsqueeze(0)
48
+
49
+ return (frames - m) / s
50
+
51
+ class TensorRandomScaling:
52
+ """Randomly scales the tensor (image) within a specified range."""
53
+ def __init__(self, scale_range=(0.8, 1.2)):
54
+ """
55
+ Args:
56
+ scale_range (tuple): A tuple (min_scale, max_scale) specifying the range for scaling.
57
+ """
58
+ assert len(scale_range) == 2, "scale_range must be a tuple with (min_scale, max_scale)."
59
+ assert scale_range[0] > 0 and scale_range[1] > 0, "Scaling factors must be positive."
60
+ self.scale_range = scale_range
61
+
62
+ def __call__(self, frames):
63
+ """
64
+ Args:
65
+ frames (torch.Tensor): Tensor of shape (batch_size, height, width).
66
+
67
+ Returns:
68
+ torch.Tensor: Scaled tensor of the same shape.
69
+ """
70
+ frames_per_slide, height, width = frames.shape
71
+
72
+ # Randomly choose a scaling factor
73
+ scale = random.uniform(*self.scale_range)
74
+
75
+ # New height and width after scaling
76
+ new_height = int(height * scale)
77
+ new_width = int(width * scale)
78
+
79
+ # Add channel dimension
80
+ frames = frames.unsqueeze(1).float()
81
+
82
+ # Resize the tensor
83
+ resized_frames = F.interpolate(
84
+ frames, # Add channel dimension: (frames_per_slide, 1, height, width)
85
+ size=(new_height, new_width),
86
+ mode='bilinear',
87
+ align_corners=False
88
+ ).squeeze(1) # Remove channel dimension: (frames_per_slide, new_height, new_width)
89
+
90
+ # Center-crop or pad to return to original size
91
+ if scale > 1.0: # Scale up: Center crop
92
+ start_y = (new_height - height) // 2
93
+ start_x = (new_width - width) // 2
94
+ scaled_frames = resized_frames[:, start_y:start_y + height, start_x:start_x + width]
95
+ else: # Scale down: Pad
96
+ pad_y = (height - new_height) // 2
97
+ pad_x = (width - new_width) // 2
98
+ padding = (pad_x, width - new_width - pad_x, pad_y, height - new_height - pad_y)
99
+ scaled_frames = F.pad(resized_frames, padding, mode='constant', value=0)
100
+
101
+ return scaled_frames.squeeze(1).type_as(frames)
102
+
103
+
104
+ class TensorCenterCrop:
105
+ """Center crop the tensor (image) within a specified range."""
106
+ def __init__(self, crop_size=(112,112)):
107
+ """
108
+ Args:
109
+ crop_size (tuple): A tuple (height, width) specifying image size after crop.
110
+ """
111
+ assert len(crop_size) == 2, "Target size must be a tuple with (height, width)."
112
+ self.crop_size = crop_size
113
+
114
+ def __call__(self, frames):
115
+ """
116
+ Args:
117
+ frames (torch.Tensor): Tensor of shape (batch_size, height, width).
118
+
119
+ Returns:
120
+ torch.Tensor: Scaled tensor of the same shape.
121
+ """
122
+ frames_per_slide, height, width = frames.shape
123
+
124
+ crop_height = self.crop_size[0]
125
+ crop_width = self.crop_size[1]
126
+ # Randomly choose a scaling factor
127
+ start_y = (height - crop_height) // 2
128
+ start_x = (width - crop_width) // 2
129
+ cropped_frames = frames[:, start_y:start_y + crop_height, start_x:start_x + crop_width]
130
+
131
+
132
+ return cropped_frames.type_as(frames)
133
+
134
+ class TensorRandomCrop:
135
+ """Center crop the tensor (image) within a specified range."""
136
+ def __init__(self, crop_size=(112,112)):
137
+ """
138
+ Args:
139
+ crop_size (tuple): A tuple (height, width) specifying image size after crop.
140
+ """
141
+ assert len(crop_size) == 2, "Target size must be a tuple with (height, width)."
142
+ self.crop_size = crop_size
143
+
144
+ def __call__(self, frames):
145
+ """
146
+ Args:
147
+ frames (torch.Tensor): Tensor of shape (batch_size, height, width).
148
+
149
+ Returns:
150
+ torch.Tensor: Scaled tensor of the same shape.
151
+ """
152
+ frames_per_slide, height, width = frames.shape
153
+
154
+ crop_height = self.crop_size[0]
155
+ crop_width = self.crop_size[1]
156
+
157
+
158
+ start_y = random.randint(0, height - crop_height)
159
+ start_x = random.randint(0, width - crop_width)
160
+
161
+ cropped_frames = frames[:, start_y:start_y + crop_height, start_x:start_x + crop_width]
162
+
163
+
164
+ return cropped_frames.type_as(frames)
165
+
166
+
167
+ class TensorResize:
168
+ """Resizes the tensor (image)"""
169
+ def __init__(self, target_size=(112,112)):
170
+ """
171
+ Args:
172
+ target_size (tuple): A tuple (height, width) specifying image size after resize.
173
+ """
174
+ assert len(target_size) == 2, "scale_range must be a tuple with (min_scale, max_scale)."
175
+ self.target_size = target_size
176
+
177
+ def __call__(self, frames):
178
+ """
179
+ Args:
180
+ frames (torch.Tensor): Tensor of shape (batch_size, height, width).
181
+
182
+ Returns:
183
+ torch.Tensor: Resized tensor of the same shape.
184
+ """
185
+ frames_per_slide, height, width = frames.shape
186
+
187
+
188
+ # New height and width after scaling
189
+ new_height = self.target_size[0]
190
+ new_width = self.target_size[1]
191
+
192
+ # Add channel dimension
193
+ frames = frames.unsqueeze(1).float()
194
+
195
+ # Resize the tensor
196
+ resized_frames = F.interpolate(
197
+ frames, # Add channel dimension: (frames_per_slide, 1, height, width)
198
+ size=(new_height, new_width),
199
+ mode='bilinear',
200
+ align_corners=False
201
+ ).squeeze(1) # Remove channel dimension: (frames_per_slide, new_height, new_width)
202
+
203
+ return resized_frames.squeeze(1).type_as(frames)
204
+
205
+
206
+
207
+ # TransformRotation
208
+ # [N, H, W] shape의 video tensor를 입력으로 받아서, angle 을 범위 내에서 랜덤하게 선택하고, angle로 모든 frame을 회전시킨다.
209
+ # torchvision.transforms.RandomRotation을 활용하면 될 것 같다.
210
+ import torchvision.transforms.functional as TF
211
+
212
+ class TensorRandomRotation:
213
+ """Randomly rotates the tensor (image) within a specified angle range."""
214
+ def __init__(self, degrees):
215
+ """
216
+ Args:
217
+ degrees (sequence or float or int): Range of degrees to select from. If degrees is a number instead of sequence like (min, max), the range of degrees will be (-degrees, +degrees).
218
+ """
219
+ if isinstance(degrees, (int, float)):
220
+ if degrees < 0:
221
+ raise ValueError("If degrees is a single number, it must be positive.")
222
+ self.degrees = (-degrees, degrees)
223
+ else:
224
+ self.degrees = degrees
225
+
226
+ def __call__(self, frames):
227
+ """
228
+ Args:
229
+ frames (torch.Tensor): Tensor of shape (frames_per_slide, height, width).
230
+
231
+ Returns:
232
+ torch.Tensor: Rotated tensor of the same shape.
233
+ """
234
+ # Randomly choose an angle
235
+ angle = random.uniform(self.degrees[0], self.degrees[1])
236
+
237
+ # Add channel dimension for each frame
238
+ frames = frames.unsqueeze(1) # Shape becomes [N, 1, H, W]
239
+
240
+ # Rotate all frames at once
241
+ rotated_frames = TF.rotate(frames, angle)
242
+
243
+ # Remove channel dimension
244
+ return rotated_frames.squeeze(1)
245
+
246
+ class TensorRandomRotation90:
247
+ """Randomly rotates the tensor (image) within a specified angle range."""
248
+ def __init__(self):
249
+ pass
250
+
251
+ def __call__(self, frames):
252
+ """
253
+ Args:
254
+ frames (torch.Tensor): Tensor of shape (frames_per_slide, height, width).
255
+
256
+ Returns:
257
+ torch.Tensor: Rotated tensor of the same shape.
258
+ """
259
+ # Randomly choose an angle
260
+ p = random.uniform(0, 1)
261
+
262
+ if p < 0.5:
263
+ return frames
264
+ else:
265
+ p2 = random.uniform(0, 1)
266
+ if p2 < 0.5:
267
+ angle = 90
268
+ else:
269
+ angle = -90
270
+
271
+ # Add channel dimension for each frame
272
+ frames = frames.unsqueeze(1) # Shape becomes [N, 1, H, W]
273
+
274
+ # Rotate all frames at once
275
+ rotated_frames = TF.rotate(frames, angle)
276
+
277
+ # Remove channel dimension
278
+ return rotated_frames.squeeze(1)
279
+
280
+ class TensorRandomShift:
281
+ """Randomly shifts the tensor (image) within a specified range."""
282
+ def __init__(self, shift_range=(0.1, 0.1)):
283
+ """
284
+ Args:
285
+ shift_range (tuple): A tuple (shift_x, shift_y) specifying the range for shifting.
286
+ """
287
+ assert len(shift_range) == 2, "shift_range must be a tuple with (shift_x, shift_y)."
288
+ self.shift_range = shift_range
289
+
290
+ def __call__(self, frames):
291
+ """
292
+ Args:
293
+ frames (torch.Tensor): Tensor of shape (batch_size, height, width).
294
+
295
+ Returns:
296
+ torch.Tensor: Shifted tensor of the same shape.
297
+ """
298
+ batch_size, height, width = frames.shape
299
+
300
+ # Randomly choose shift values
301
+ shift_x = random.uniform(-self.shift_range[0], self.shift_range[0])
302
+ shift_y = random.uniform(-self.shift_range[1], self.shift_range[1])
303
+
304
+ # Add channel dimension
305
+ frames = frames.unsqueeze(1).float()
306
+
307
+ # Create the affine transformation matrix
308
+ theta = torch.tensor([[1.0, 0.0, shift_x], [0.0, 1.0, shift_y]], dtype=torch.float)
309
+ theta = theta.unsqueeze(0).repeat(batch_size, 1, 1)
310
+
311
+ # Create the grid
312
+ grid = F.affine_grid(theta, frames.size(), align_corners=False)
313
+
314
+ # Apply the grid to the frames
315
+ shifted_frames = F.grid_sample(frames, grid, align_corners=False)
316
+
317
+ # Remove channel dimension
318
+ return shifted_frames.squeeze(1)