braindecode 1.8.1.dev170153392__tar.gz → 1.8.1.dev170208067__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. {braindecode-1.8.1.dev170153392/braindecode.egg-info → braindecode-1.8.1.dev170208067}/PKG-INFO +1 -1
  2. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/augmentation/__init__.py +2 -0
  3. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/augmentation/base.py +7 -1
  4. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/augmentation/functional.py +133 -13
  5. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/augmentation/transforms.py +104 -2
  6. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/base.py +3 -1
  7. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/mne.py +5 -0
  8. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/tuh.py +2 -1
  9. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datautil/serialization.py +11 -4
  10. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/functional/initialization.py +14 -9
  11. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/atcnet.py +11 -8
  12. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/base.py +13 -1
  13. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/biot.py +4 -2
  14. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/ctnet.py +9 -3
  15. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/guetschel2026.py +8 -8
  16. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/labram.py +11 -1
  17. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/luna.py +4 -1
  18. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/medformer.py +12 -15
  19. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/neurorvq_tokenizer.py +28 -6
  20. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/reve.py +5 -11
  21. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/sinc_shallow.py +15 -0
  22. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/tmsanet.py +11 -0
  23. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/zuna.py +10 -10
  24. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/attention.py +25 -10
  25. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/blocks.py +21 -85
  26. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/preprocessing/eegprep_preprocess.py +6 -3
  27. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/preprocessing/preprocess.py +2 -0
  28. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/preprocessing/windowers.py +28 -17
  29. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/regressor.py +6 -1
  30. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/samplers/base.py +13 -2
  31. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/training/scoring.py +4 -1
  32. braindecode-1.8.1.dev170208067/braindecode/version.py +1 -0
  33. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067/braindecode.egg-info}/PKG-INFO +1 -1
  34. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/api.rst +4 -0
  35. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/whats_new.rst +79 -22
  36. braindecode-1.8.1.dev170153392/braindecode/version.py +0 -1
  37. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/LICENSE.txt +0 -0
  38. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/MANIFEST.in +0 -0
  39. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/NOTICE.txt +0 -0
  40. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/README.rst +0 -0
  41. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/__init__.py +0 -0
  42. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/classifier.py +0 -0
  43. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/__init__.py +0 -0
  44. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/_notebook_viewer.py +0 -0
  45. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/bbci.py +0 -0
  46. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/bcicomp.py +0 -0
  47. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/bids/__init__.py +0 -0
  48. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/bids/datasets.py +0 -0
  49. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/bids/format.py +0 -0
  50. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/bids/hub.py +0 -0
  51. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/bids/hub_format.py +0 -0
  52. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/bids/hub_io.py +0 -0
  53. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/bids/hub_validation.py +0 -0
  54. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/bids/iterable.py +0 -0
  55. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/chb_mit.py +0 -0
  56. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/collate.py +0 -0
  57. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/moabb.py +0 -0
  58. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/nmt.py +0 -0
  59. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/registry.py +0 -0
  60. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/siena.py +0 -0
  61. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  62. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/sleep_physionet.py +0 -0
  63. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/utils.py +0 -0
  64. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datasets/xy.py +0 -0
  65. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datautil/__init__.py +0 -0
  66. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datautil/channel_utils.py +0 -0
  67. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datautil/hub_formats.py +0 -0
  68. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/datautil/util.py +0 -0
  69. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/eegneuralnet.py +0 -0
  70. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/functional/__init__.py +0 -0
  71. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/functional/_real_dft.py +0 -0
  72. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/functional/functions.py +0 -0
  73. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/__init__.py +0 -0
  74. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/attentionbasenet.py +0 -0
  75. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/attn_sleep.py +0 -0
  76. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/axon.py +0 -0
  77. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/barista.py +0 -0
  78. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/bendr.py +0 -0
  79. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/brainbert.py +0 -0
  80. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/brainmodule.py +0 -0
  81. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/brainomni.py +0 -0
  82. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/brant.py +0 -0
  83. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/cbramod.py +0 -0
  84. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/codebrain.py +0 -0
  85. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/config.py +0 -0
  86. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/contrawr.py +0 -0
  87. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/csbrain.py +0 -0
  88. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/dance.py +0 -0
  89. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/deep4.py +0 -0
  90. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/deepsleepnet.py +0 -0
  91. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/dgcnn.py +0 -0
  92. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/diver1.py +0 -0
  93. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/duin.py +0 -0
  94. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/eeg_clip.py +0 -0
  95. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/eegconformer.py +0 -0
  96. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/eegdino.py +0 -0
  97. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/eeginception_erp.py +0 -0
  98. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/eeginception_mi.py +0 -0
  99. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/eegitnet.py +0 -0
  100. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/eegminer.py +0 -0
  101. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/eegnet.py +0 -0
  102. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/eegnex.py +0 -0
  103. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/eegpt.py +0 -0
  104. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/eegsimpleconv.py +0 -0
  105. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/eegsym.py +0 -0
  106. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/eegtcnet.py +0 -0
  107. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/emg2qwerty.py +0 -0
  108. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/epint.py +0 -0
  109. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/fbcnet.py +0 -0
  110. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/fblightconvnet.py +0 -0
  111. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/fbmsnet.py +0 -0
  112. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/gcnsnet.py +0 -0
  113. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/hybrid.py +0 -0
  114. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/ifnet.py +0 -0
  115. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/mapa.py +0 -0
  116. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/meta_neuromotor.py +0 -0
  117. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/mirepnet.py +0 -0
  118. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/mscformer.py +0 -0
  119. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/msvtnet.py +0 -0
  120. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/mvpformer.py +0 -0
  121. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/neuropose.py +0 -0
  122. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/neurorvq.py +0 -0
  123. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/patchedtransformer.py +0 -0
  124. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/popt.py +0 -0
  125. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/sccnet.py +0 -0
  126. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/seizure_transformer.py +0 -0
  127. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/sensingdynamics.py +0 -0
  128. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/shallow_fbcsp.py +0 -0
  129. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/signal_jepa.py +0 -0
  130. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
  131. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  132. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/sleepfm.py +0 -0
  133. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/sparcnet.py +0 -0
  134. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/sstdpn.py +0 -0
  135. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/steegformer.py +0 -0
  136. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/summary.csv +0 -0
  137. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/syncnet.py +0 -0
  138. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/tcformer.py +0 -0
  139. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/tcn.py +0 -0
  140. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/tfm_tokenizer.py +0 -0
  141. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/tidnet.py +0 -0
  142. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/tsinception.py +0 -0
  143. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/usleep.py +0 -0
  144. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/util.py +0 -0
  145. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/models/vemg2pose.py +0 -0
  146. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/__init__.py +0 -0
  147. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/activation.py +0 -0
  148. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/channels.py +0 -0
  149. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/convolution.py +0 -0
  150. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/dance_modules.py +0 -0
  151. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/filter.py +0 -0
  152. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/layers.py +0 -0
  153. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/linear.py +0 -0
  154. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/linear_attention.py +0 -0
  155. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/parametrization.py +0 -0
  156. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/popt_modules.py +0 -0
  157. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/quantization.py +0 -0
  158. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/stats.py +0 -0
  159. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/util.py +0 -0
  160. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/modules/wrapper.py +0 -0
  161. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/preprocessing/__init__.py +0 -0
  162. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/preprocessing/mne_preprocess.py +0 -0
  163. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/preprocessing/util.py +0 -0
  164. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/samplers/__init__.py +0 -0
  165. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/samplers/ssl.py +0 -0
  166. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/training/__init__.py +0 -0
  167. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/training/callbacks.py +0 -0
  168. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/training/losses.py +0 -0
  169. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/util.py +0 -0
  170. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/visualization/__init__.py +0 -0
  171. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/visualization/activations.py +0 -0
  172. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/visualization/attribution.py +0 -0
  173. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/visualization/confusion_matrices.py +0 -0
  174. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/visualization/frequency.py +0 -0
  175. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/visualization/metrics.py +0 -0
  176. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/visualization/sanity.py +0 -0
  177. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode/visualization/topology.py +0 -0
  178. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode.egg-info/SOURCES.txt +0 -0
  179. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode.egg-info/dependency_links.txt +0 -0
  180. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode.egg-info/requires.txt +0 -0
  181. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/braindecode.egg-info/top_level.txt +0 -0
  182. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/Makefile +0 -0
  183. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/_templates/autosummary/class.rst +0 -0
  184. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  185. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/_templates/autosummary/function.rst +0 -0
  186. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  187. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/agent_docs.rst +0 -0
  188. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/cite.rst +0 -0
  189. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/conf.py +0 -0
  190. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/help.rst +0 -0
  191. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/index.rst +0 -0
  192. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/install/install.rst +0 -0
  193. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/install/install_pip.rst +0 -0
  194. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/install/install_source.rst +0 -0
  195. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/models/categorization/attention.rst +0 -0
  196. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/models/categorization/channel.rst +0 -0
  197. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/models/categorization/convolution.rst +0 -0
  198. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/models/categorization/filterbank.rst +0 -0
  199. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/models/categorization/gnn.rst +0 -0
  200. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/models/categorization/interpretable.rst +0 -0
  201. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/models/categorization/lbm.rst +0 -0
  202. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/models/categorization/recurrent.rst +0 -0
  203. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/models/categorization/spd.rst +0 -0
  204. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/models/models.rst +0 -0
  205. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/models/models_categorization.rst +0 -0
  206. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/models/models_table.rst +0 -0
  207. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/models/models_visualization.rst +0 -0
  208. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/sg_execution_times.rst +0 -0
  209. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/docs/user_guide/channel_strategies.rst +0 -0
  210. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/pyproject.toml +0 -0
  211. {braindecode-1.8.1.dev170153392 → braindecode-1.8.1.dev170208067}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.8.1.dev170153392
3
+ Version: 1.8.1.dev170208067
4
4
  Summary: Deep learning software to decode EEG, ECG or MEG signals
5
5
  Author-email: Robin Tibor Schirrmeister <robintibor@gmail.com>, Bruno Aristimunha Pinto <b.aristimunha@gmail.com>, Alexandre Gramfort <agramfort@meta.com>
6
6
  Maintainer-email: Alexandre Gramfort <agramfort@meta.com>, Bruno Aristimunha Pinto <b.aristimunha@gmail.com>, Robin Tibor Schirrmeister <robintibor@gmail.com>
@@ -14,6 +14,7 @@ from .transforms import (
14
14
  FrequencyShift,
15
15
  FTSurrogate,
16
16
  GaussianNoise,
17
+ LabelSmoothing,
17
18
  MaskEncoding,
18
19
  Mixup,
19
20
  SegmentationReconstruction,
@@ -40,6 +41,7 @@ __all__ = [
40
41
  "CutMix",
41
42
  "ChannelsDropout",
42
43
  "GaussianNoise",
44
+ "LabelSmoothing",
43
45
  "ChannelsSymmetry",
44
46
  "SmoothTimeMask",
45
47
  "BandstopFilter",
@@ -171,7 +171,13 @@ class Compose(Transform):
171
171
  self.transforms = transforms
172
172
  super().__init__()
173
173
 
174
- def forward(self, X, y):
174
+ def forward(self, X, y=None):
175
+ # like Transform.forward, return only X when no target is given (each
176
+ # transform then returns a single tensor, not an (X, y) pair)
177
+ if y is None:
178
+ for transform in self.transforms:
179
+ X = transform(X)
180
+ return X
175
181
  for transform in self.transforms:
176
182
  X, y = transform(X, y)
177
183
  return X, y
@@ -19,7 +19,22 @@ from mne.filter import notch_filter
19
19
  from scipy.interpolate import Rbf
20
20
  from sklearn.utils import check_random_state
21
21
  from torch.fft import fft, ifft
22
- from torch.nn.functional import pad
22
+ from torch.nn.functional import one_hot, pad
23
+
24
+
25
+ def _max_float_dtype(device: torch.device | str) -> torch.dtype:
26
+ """float64, or float32 on Apple MPS, which has no float64."""
27
+ return torch.float32 if torch.device(device).type == "mps" else torch.float64
28
+
29
+
30
+ def _to_device(t: torch.Tensor, device: torch.device | str) -> torch.Tensor:
31
+ """Move ``t`` to ``device``, in single precision on MPS (no float64 there)."""
32
+ if torch.device(device).type == "mps":
33
+ if t.dtype == torch.float64:
34
+ return t.float().to(device)
35
+ if t.dtype == torch.complex128:
36
+ return t.to(torch.complex64).to(device)
37
+ return t.to(device)
23
38
 
24
39
 
25
40
  def identity(X: torch.Tensor, y: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
@@ -92,10 +107,11 @@ def _new_random_fft_phase_odd(
92
107
  rng = check_random_state(random_state)
93
108
  random_phase = torch.from_numpy(
94
109
  2j * np.pi * rng.random((batch_size, c, (n - 1) // 2))
95
- ).to(device)
110
+ )
111
+ random_phase = _to_device(random_phase, device)
96
112
  return torch.cat(
97
113
  [
98
- torch.zeros((batch_size, c, 1), device=device),
114
+ torch.zeros((batch_size, c, 1), device=device, dtype=random_phase.dtype),
99
115
  random_phase,
100
116
  -torch.flip(random_phase, [-1]),
101
117
  ],
@@ -113,12 +129,13 @@ def _new_random_fft_phase_even(
113
129
  rng = check_random_state(random_state)
114
130
  random_phase = torch.from_numpy(
115
131
  2j * np.pi * rng.random((batch_size, c, n // 2 - 1))
116
- ).to(device)
132
+ )
133
+ random_phase = _to_device(random_phase, device)
117
134
  return torch.cat(
118
135
  [
119
- torch.zeros((batch_size, c, 1), device=device),
136
+ torch.zeros((batch_size, c, 1), device=device, dtype=random_phase.dtype),
120
137
  random_phase,
121
- torch.zeros((batch_size, c, 1), device=device),
138
+ torch.zeros((batch_size, c, 1), device=device, dtype=random_phase.dtype),
122
139
  -torch.flip(random_phase, [-1]),
123
140
  ],
124
141
  dim=-1,
@@ -178,7 +195,7 @@ def ft_surrogate(
178
195
  and 0 <= phase_noise_magnitude <= 1
179
196
  ), f"eps must be a float between 0 and 1. Got {phase_noise_magnitude}."
180
197
 
181
- f = fft(X.double(), dim=-1)
198
+ f = fft(X.to(_max_float_dtype(X.device)), dim=-1)
182
199
  device = X.device
183
200
 
184
201
  n = f.shape[-1]
@@ -580,6 +597,7 @@ def _frequency_shift(X: torch.Tensor, fs: float, f_shift: float) -> torch.Tensor
580
597
  _f_shift = torch.as_tensor(f_shift).float()
581
598
  else:
582
599
  raise ValueError(f"Invalid f_shift type: {type(f_shift)}")
600
+ _f_shift = _f_shift.to(X.device)
583
601
  f_shift_stack = _f_shift.repeat(N_padded, n_channels, 1)
584
602
  reshaped_f_shift = f_shift_stack.permute(
585
603
  *torch.arange(f_shift_stack.ndim - 1, -1, -1)
@@ -911,7 +929,15 @@ def _rotate_signals(
911
929
  sensors_positions_matrix: torch.Tensor,
912
930
  spherical: bool = True,
913
931
  ) -> torch.Tensor:
914
- sensors_positions_matrix = sensors_positions_matrix.to(X.device)
932
+ if X.device.type == "mps":
933
+ # MPS has no float64: compute the small (n_chans x n_chans) spherical
934
+ # spline matrices on CPU in double precision, only move the result
935
+ # (two separate steps: a combined device + dtype .to() from MPS
936
+ # returns zeros with some torch versions)
937
+ sensors_positions_matrix = sensors_positions_matrix.cpu().double()
938
+ rotations = [rotation.cpu().double() for rotation in rotations]
939
+ else:
940
+ sensors_positions_matrix = sensors_positions_matrix.to(X.device)
915
941
  rot_sensors_matrices = [
916
942
  rotation.matmul(sensors_positions_matrix) for rotation in rotations
917
943
  ]
@@ -921,9 +947,10 @@ def _rotate_signals(
921
947
  torch.as_tensor(
922
948
  _torch_make_interpolation_matrix(
923
949
  sensors_positions_matrix.T, rot_sensors_matrix.T
924
- ),
925
- device=X.device,
926
- ).float()
950
+ )
951
+ )
952
+ .float()
953
+ .to(X.device)
927
954
  for rot_sensors_matrix in rot_sensors_matrices
928
955
  ]
929
956
  )
@@ -1062,10 +1089,12 @@ def mixup(
1062
1089
  Online: https://arxiv.org/abs/1710.09412
1063
1090
  .. [2] https://github.com/facebookresearch/mixup-cifar10/blob/master/train.py
1064
1091
  """
1065
- device = X.device
1066
1092
  batch_size, n_channels, n_times = X.shape
1067
1093
 
1068
- X_mix = torch.zeros((batch_size, n_channels, n_times)).to(device)
1094
+ X_mix = X.new_zeros(
1095
+ (batch_size, n_channels, n_times),
1096
+ dtype=X.dtype if X.is_floating_point() else torch.get_default_dtype(),
1097
+ )
1069
1098
  y_a = y.clone()
1070
1099
  y_b = y[idx_perm].clone()
1071
1100
 
@@ -1123,6 +1152,97 @@ def cutmix(
1123
1152
  return X_mix, (y.clone(), y[idx_perm].clone(), lam)
1124
1153
 
1125
1154
 
1155
+ def label_smoothing(
1156
+ X: torch.Tensor,
1157
+ y: torch.Tensor,
1158
+ epsilon: float,
1159
+ num_classes: int | None = None,
1160
+ ) -> tuple[torch.Tensor, torch.Tensor]:
1161
+ """Smooth targets toward the uniform distribution over the classes.
1162
+
1163
+ See [1]_ for details.
1164
+
1165
+ Parameters
1166
+ ----------
1167
+ X : torch.Tensor
1168
+ EEG data in form ``batch_size, n_channels, n_times``. Returned
1169
+ unchanged.
1170
+ y : torch.Tensor
1171
+ Target of length ``batch_size`` holding class indices (float values
1172
+ are accepted when they are integral), or a floating-point tensor of
1173
+ shape ``batch_size, num_classes`` holding target distributions.
1174
+ epsilon : float
1175
+ Smoothing parameter between 0 and 1: the weight of the uniform
1176
+ distribution mixed into the targets. ``0`` returns the unsmoothed
1177
+ targets.
1178
+ num_classes : int | None, optional
1179
+ Number of classes. Required when ``y`` holds class indices; when
1180
+ ``y`` already holds distributions, it must match the size of the
1181
+ last dimension of ``y``. Defaults to None.
1182
+
1183
+ Returns
1184
+ -------
1185
+ tuple
1186
+ ``X``, ``y``. Where ``X`` is unchanged and ``y`` is a
1187
+ floating-point tensor of shape ``batch_size, num_classes`` whose
1188
+ rows sum to one.
1189
+
1190
+ References
1191
+ ----------
1192
+ .. [1] Christian Szegedy, Vincent Vanhoucke, Jonathon Shlens and
1193
+ Zbigniew Wojna (2016). Rethinking the Inception Architecture for
1194
+ Computer Vision. In 2016 IEEE Conference on Computer Vision and
1195
+ Pattern Recognition (CVPR), pp. 2818-2826.
1196
+ Online: https://arxiv.org/abs/1512.00567
1197
+ """
1198
+ if not isinstance(epsilon, Real) or not 0.0 <= float(epsilon) <= 1.0:
1199
+ raise ValueError(
1200
+ f"epsilon should be a real number between 0 and 1. Got {epsilon!r}."
1201
+ )
1202
+ if num_classes is not None and (
1203
+ not isinstance(num_classes, int)
1204
+ or isinstance(num_classes, bool)
1205
+ or num_classes < 2
1206
+ ):
1207
+ raise ValueError(
1208
+ f"num_classes should be an integer of at least 2. Got {num_classes!r}."
1209
+ )
1210
+
1211
+ if y.dim() == 1:
1212
+ # class-index targets: smooth their one-hot encoding
1213
+ if num_classes is None:
1214
+ raise ValueError("num_classes is required when y holds class indices.")
1215
+ if not torch.all(y == y.floor()):
1216
+ raise ValueError(
1217
+ "y holds non-integral values; class-index targets should be "
1218
+ "integers or integral floats."
1219
+ )
1220
+ if y.numel() > 0 and (y.min() < 0 or y.max() >= num_classes):
1221
+ raise ValueError(f"y holds class indices outside [0, {num_classes}).")
1222
+ one_hot_y = one_hot(y.long(), num_classes).to(dtype=X.dtype)
1223
+ return X, one_hot_y * (1.0 - epsilon) + epsilon / num_classes
1224
+
1225
+ if y.is_floating_point() and y.dim() >= 2:
1226
+ # target distributions: interpolate them toward the uniform one
1227
+ n_classes = y.shape[-1]
1228
+ if num_classes is not None and num_classes != n_classes:
1229
+ raise ValueError(
1230
+ f"num_classes ({num_classes}) does not match the size of the "
1231
+ f"last dimension of y ({n_classes})."
1232
+ )
1233
+ if n_classes < 2:
1234
+ raise ValueError(
1235
+ f"y should hold distributions over at least 2 classes. Got {n_classes}."
1236
+ )
1237
+ return X, y * (1.0 - epsilon) + epsilon / n_classes
1238
+
1239
+ raise ValueError(
1240
+ "y should hold class indices or floating-point target distributions "
1241
+ f"with a class dimension; got dtype {y.dtype} and shape "
1242
+ f"{tuple(y.shape)}."
1243
+ )
1244
+
1245
+
1126
1246
  def segmentation_reconstruction(
1127
1247
  X: torch.Tensor,
1128
1248
  y: torch.Tensor,
@@ -18,6 +18,7 @@ from braindecode.util import resolve_montage_name
18
18
 
19
19
  from .base import Transform
20
20
  from .functional import (
21
+ _max_float_dtype,
21
22
  amplitude_scale,
22
23
  band_rotation,
23
24
  bandstop_filter,
@@ -29,6 +30,7 @@ from .functional import (
29
30
  frequency_shift,
30
31
  ft_surrogate,
31
32
  gaussian_noise,
33
+ label_smoothing,
32
34
  mask_encoding,
33
35
  mixup,
34
36
  segmentation_reconstruction,
@@ -494,6 +496,7 @@ class SmoothTimeMask(Transform):
494
496
  size=X.shape[0],
495
497
  ),
496
498
  device=X.device,
499
+ dtype=_max_float_dtype(X.device),
497
500
  ) * (seq_length - mask_len_samples)
498
501
  return {
499
502
  "mask_start_per_sample": mask_start,
@@ -675,7 +678,11 @@ class FrequencyShift(Transform):
675
678
  return super().get_augmentation_params(*batch)
676
679
  X = batch[0]
677
680
 
678
- u = torch.as_tensor(self.rng.uniform(size=X.shape[0]), device=X.device)
681
+ u = torch.as_tensor(
682
+ self.rng.uniform(size=X.shape[0]),
683
+ device=X.device,
684
+ dtype=_max_float_dtype(X.device),
685
+ )
679
686
  max_delta_freq = self.max_delta_freq
680
687
  if isinstance(max_delta_freq, torch.Tensor):
681
688
  max_delta_freq = max_delta_freq.to(X.device)
@@ -833,7 +840,10 @@ class SensorsRotation(Transform):
833
840
  if isinstance(max_degrees, torch.Tensor):
834
841
  max_degrees = max_degrees.to(X.device)
835
842
  random_angles = (
836
- torch.as_tensor(u, device=X.device) * 2 * max_degrees - max_degrees
843
+ torch.as_tensor(u, device=X.device, dtype=_max_float_dtype(X.device))
844
+ * 2
845
+ * max_degrees
846
+ - max_degrees
837
847
  )
838
848
  return {
839
849
  "sensors_positions_matrix": self.sensors_positions_matrix,
@@ -1146,6 +1156,98 @@ class CutMix(Mixup):
1146
1156
  return dict(params, cut_t_start=start, cut_t_len=end - start)
1147
1157
 
1148
1158
 
1159
+ class LabelSmoothing(Transform):
1160
+ """Label smoothing from Szegedy et al. (2016) [1]_.
1161
+
1162
+ Replaces each target with its convex combination with the uniform
1163
+ distribution over the classes, penalizing over-confident predictions.
1164
+ The signals are returned unchanged; only the targets change.
1165
+
1166
+ The smoothed targets are floating-point distributions of shape
1167
+ ``batch_size, num_classes`` (each row sums to one), so the training
1168
+ loss must accept target distributions, e.g. soft cross-entropy
1169
+ ``-(y * torch.log_softmax(logits, dim=-1)).sum(-1).mean()`` or
1170
+ ``torch.nn.KLDivLoss``. The transform composes before target-mixing
1171
+ transforms such as :class:`braindecode.augmentation.Mixup`, whose
1172
+ fractional-target path then mixes the smoothed distributions. The
1173
+ fixed-expansion mode (``n_augmentation > 0``) of
1174
+ :class:`braindecode.augmentation.AugmentedDataLoader` is not supported:
1175
+ it cannot concatenate the unsmoothed original targets with the reshaped
1176
+ smoothed copies.
1177
+
1178
+ Parameters
1179
+ ----------
1180
+ epsilon : float
1181
+ Smoothing parameter between 0 and 1: the weight of the uniform
1182
+ distribution mixed into the targets. ``0`` disables smoothing.
1183
+ num_classes : int | None, optional
1184
+ Number of classes. Required when the targets are class indices;
1185
+ when the targets are already distributions of shape
1186
+ ``batch_size, num_classes``, it must match their last dimension.
1187
+ Defaults to None.
1188
+ random_state : int | numpy.random.Generator, optional
1189
+ Seed to be used to instantiate numpy random number generator
1190
+ instance. The transform is deterministic, so the seed only feeds
1191
+ the application-probability machinery, which is inactive here.
1192
+ Defaults to None.
1193
+
1194
+ References
1195
+ ----------
1196
+ .. [1] Christian Szegedy, Vincent Vanhoucke, Jonathon Shlens and
1197
+ Zbigniew Wojna (2016). Rethinking the Inception Architecture for
1198
+ Computer Vision. In 2016 IEEE Conference on Computer Vision and
1199
+ Pattern Recognition (CVPR), pp. 2818-2826.
1200
+ Online: https://arxiv.org/abs/1512.00567
1201
+ """
1202
+
1203
+ operation = staticmethod(label_smoothing) # type: ignore[assignment]
1204
+
1205
+ def __init__(self, epsilon, num_classes=None, random_state=None):
1206
+ super().__init__(
1207
+ probability=1.0, # LabelSmoothing has to be applied to whole batches
1208
+ random_state=random_state,
1209
+ )
1210
+ if not isinstance(epsilon, Real) or not 0.0 <= float(epsilon) <= 1.0:
1211
+ raise ValueError(
1212
+ f"epsilon should be a real number between 0 and 1. Got {epsilon!r}."
1213
+ )
1214
+ if num_classes is not None and (
1215
+ not isinstance(num_classes, int)
1216
+ or isinstance(num_classes, bool)
1217
+ or num_classes < 2
1218
+ ):
1219
+ raise ValueError(
1220
+ f"num_classes should be an integer of at least 2. Got {num_classes!r}."
1221
+ )
1222
+ self.epsilon = epsilon
1223
+ self.num_classes = num_classes
1224
+
1225
+ def get_augmentation_params(self, *batch):
1226
+ """Return transform parameters.
1227
+
1228
+ Parameters
1229
+ ----------
1230
+ X : tensor.Tensor
1231
+ The data.
1232
+ y : tensor.Tensor
1233
+ The labels.
1234
+
1235
+ Returns
1236
+ -------
1237
+ params : dict
1238
+ Contains
1239
+
1240
+ * epsilon : float
1241
+ Smoothing parameter between 0 and 1.
1242
+ * num_classes : int | None
1243
+ The number of classes.
1244
+ """
1245
+ return {
1246
+ "epsilon": self.epsilon,
1247
+ "num_classes": self.num_classes,
1248
+ }
1249
+
1250
+
1149
1251
  class SegmentationReconstruction(Transform):
1150
1252
  """Segmentation Reconstruction from Lotte (2015) [Lotte2015]_.
1151
1253
 
@@ -634,7 +634,9 @@ class RecordDataset(Dataset[tuple[np.ndarray, int | str, tuple[int, int, int]]])
634
634
  f"'{key}' already in description. Please "
635
635
  f"rename or set overwrite to True."
636
636
  )
637
- self._description.pop(key)
637
+ # drop on a copy: windows datasets share the description
638
+ # Series of the dataset they were created from
639
+ self._description = self._description.drop(key)
638
640
  self._description = pd.concat([self.description, description])
639
641
 
640
642
  @property
@@ -159,6 +159,11 @@ def create_from_mne_epochs(
159
159
 
160
160
  list_of_windows_ds = []
161
161
  for i, epochs in enumerate(list_of_epochs):
162
+ # drop rejected epochs first (on a copy) so that iterating over the
163
+ # epochs stays aligned with ``epochs.events``; preloaded epochs have
164
+ # already dropped them, so skip copying their data
165
+ if not epochs.preload:
166
+ epochs = epochs.copy().drop_bad()
162
167
  event_descriptions = epochs.events[:, 2]
163
168
  original_trial_starts = epochs.events[:, 0]
164
169
  stop = len(epochs.times) - window_size_samples
@@ -122,7 +122,8 @@ class TUH(BaseConcatDataset):
122
122
  # Assume it is an integer specifying number
123
123
  # of recordings to load
124
124
  recording_ids = range(recording_ids)
125
- descriptions = descriptions[recording_ids]
125
+ # select by chronological position, not by (file listing) label
126
+ descriptions = descriptions.iloc[:, list(recording_ids)]
126
127
 
127
128
  # workaround to ensure warnings are suppressed when running in parallel
128
129
  def create_dataset(*args, **kwargs):
@@ -140,15 +140,19 @@ def _load_signals(fif_file, preload, is_raw):
140
140
  with open(pkl_file, "rb") as f:
141
141
  signals = pickle.load(f)
142
142
 
143
- if all(Path(f).exists() for f in signals.filenames):
143
+ # The pickle stores absolute paths: check that they exist and point to
144
+ # this fif file, not to the folder the dataset was copied from.
145
+ if all(Path(f).exists() for f in signals.filenames) and (
146
+ Path(signals.filenames[0]).resolve() == fif_file.resolve()
147
+ ):
144
148
  if preload:
145
149
  signals.load_data()
146
150
  return _compact_fif_tags(signals)
147
151
  else: # This may happen if the file has been moved together with the pickle file.
148
152
  warnings.warn(
149
153
  f"Pickle file {pkl_file} exists, but the referenced fif "
150
- "file(s) do not exist. Will read the fif file(s) directly "
151
- "and re-create the pickle file.",
154
+ "file(s) do not exist or are not next to it. Will read the "
155
+ "fif file(s) directly and re-create the pickle file.",
152
156
  UserWarning,
153
157
  )
154
158
 
@@ -220,7 +224,10 @@ def load_concat_dataset(path, preload, ids_to_load=None, target_name=None, n_job
220
224
  # target_name.json, raw_preproc_kwargs.json, window_kwargs.json,
221
225
  # window_preproc_kwargs.json
222
226
  if ids_to_load is None:
223
- ids_to_load = [p.name for p in path.iterdir()]
227
+ # skip stray entries such as .DS_Store or a README next to the datasets
228
+ ids_to_load = [
229
+ p.name for p in path.iterdir() if p.is_dir() and p.name.isdigit()
230
+ ]
224
231
  ids_to_load = sorted(ids_to_load, key=lambda i: int(i))
225
232
  ids_to_load = [str(i) for i in ids_to_load]
226
233
  first_raw_fif_path = path / ids_to_load[0] / f"{ids_to_load[0]}-raw.fif"
@@ -1,25 +1,30 @@
1
1
  import math
2
2
 
3
+ import torch
3
4
  from torch import nn
4
5
 
5
6
 
6
7
  def glorot_weight_zero_bias(model):
7
- """Initialize parameters of all modules by initializing weights with.
8
+ """Set the weights of BatchNorm layers to one and all biases to zero.
8
9
 
9
- glorot uniform/xavier initialization, and setting biases to zero. Weights from
10
- batch norm layers are set to 1.
10
+ Despite its name, this function does not apply the Glorot (Xavier)
11
+ initialization: other weights keep the initialization of their layer
12
+ (PyTorch's default, or Xavier uniform for the max-norm constrained layers
13
+ such as :class:`braindecode.modules.Conv2dWithConstraint`). The name is
14
+ kept for backward compatibility.
11
15
 
12
16
  Parameters
13
17
  ----------
14
18
  model : Module
15
19
  """
16
20
  for module in model.modules():
17
- if hasattr(module, "weight"):
18
- if "BatchNorm" in module.__class__.__name__:
19
- nn.init.constant_(module.weight, 1)
20
- if hasattr(module, "bias"):
21
- if module.bias is not None:
22
- nn.init.constant_(module.bias, 0)
21
+ # ``weight``/``bias`` can be None (e.g. BatchNorm with affine=False)
22
+ weight = getattr(module, "weight", None)
23
+ if isinstance(weight, torch.Tensor) and "BatchNorm" in type(module).__name__:
24
+ nn.init.constant_(weight, 1)
25
+ bias = getattr(module, "bias", None)
26
+ if isinstance(bias, torch.Tensor):
27
+ nn.init.constant_(bias, 0)
23
28
 
24
29
 
25
30
  def rescale_parameter(param, layer_id):
@@ -444,8 +444,10 @@ class ATCNet(EEGModuleMixin, nn.Module):
444
444
  # ----- Sliding window -----
445
445
  sw_concat: list[torch.Tensor] = [] # to store sliding window outputs
446
446
  # for w in range(self.n_windows):
447
- for idx, (attention, tcn_module, final_layer) in enumerate(
448
- zip(self.attention_blocks, self.temporal_conv_nets, self.final_layer)
447
+ # (final_layer is not zipped in: with concat=True it holds a single
448
+ # layer, which would stop the loop after the first window)
449
+ for idx, (attention, tcn_module) in enumerate(
450
+ zip(self.attention_blocks, self.temporal_conv_nets)
449
451
  ):
450
452
  conv_feat_w = conv_feat[..., idx : idx + self.Tw]
451
453
  # Dimension: (batch_size, F2, Tw)
@@ -458,14 +460,15 @@ class ATCNet(EEGModuleMixin, nn.Module):
458
460
  tcn_feat = tcn_module(att_feat)[..., -1]
459
461
  # Dimension: (batch_size, F2)
460
462
 
461
- # Outputs of sliding window can be either averaged after being
462
- # mapped by dense layer or concatenated then mapped by a dense
463
- # layer
464
- if not self.concat:
465
- tcn_feat = final_layer(tcn_feat)
466
-
467
463
  sw_concat.append(tcn_feat)
468
464
 
465
+ # Outputs of sliding window can be either averaged after being
466
+ # mapped by dense layer or concatenated then mapped by a dense
467
+ # layer
468
+ if not self.concat:
469
+ for idx, final_layer in enumerate(self.final_layer):
470
+ sw_concat[idx] = final_layer(sw_concat[idx])
471
+
469
472
  # ----- Aggregation and prediction -----
470
473
  if self.concat:
471
474
  sw_concat_agg = torch.cat(sw_concat, dim=1)
@@ -521,6 +521,11 @@ class EEGModuleMixin(_BaseHubMixin, metaclass=_BraindecodeDocstringMeta):
521
521
  output_shape : tuple[int, ...]
522
522
  shape of the network output for `batch_size==1` (1, ...)
523
523
  """
524
+ # Run in eval mode, so that the probe input does not update BatchNorm
525
+ # running stats or draw dropout masks; restore each module's own mode
526
+ # afterwards (some may have been put in eval mode on purpose).
527
+ modes = {module: module.training for module in self.modules()}
528
+ self.eval()
524
529
  with torch.inference_mode():
525
530
  try:
526
531
  return tuple(
@@ -540,6 +545,9 @@ class EEGModuleMixin(_BaseHubMixin, metaclass=_BraindecodeDocstringMeta):
540
545
  if error is None:
541
546
  raise
542
547
  raise error from exc
548
+ finally:
549
+ for module, training in modes.items():
550
+ module.training = training
543
551
 
544
552
  def get_config(self) -> dict:
545
553
  """Return a JSON-serializable dict of all ``__init__`` parameters.
@@ -623,7 +631,11 @@ class EEGModuleMixin(_BaseHubMixin, metaclass=_BraindecodeDocstringMeta):
623
631
  ``"pad"``.
624
632
  """
625
633
  legacy = getattr(cls, "_legacy_on_non_divisible", None)
626
- if legacy is not None and "on_non_divisible" not in kwargs:
634
+ if legacy is None or "on_non_divisible" in kwargs:
635
+ return
636
+ # A subclass with its own signature may not take the argument.
637
+ params = inspect.signature(cls.__init__).parameters.values()
638
+ if any(p.name == "on_non_divisible" or p.kind is p.VAR_KEYWORD for p in params):
627
639
  kwargs["on_non_divisible"] = legacy
628
640
 
629
641
  def _set_n_outputs(self, n_outputs: int) -> None:
@@ -186,10 +186,12 @@ class BIOT(EEGModuleMixin, nn.Module):
186
186
  warn(
187
187
  "The hop length is larger than the sampling frequency. "
188
188
  + "This may cause aliasing. Consider using a smaller "
189
- "hop length.",
189
+ "hop length. Using sfreq // 2 instead.",
190
190
  UserWarning,
191
191
  )
192
- hop_length = self.sfreq // 2
192
+ # torch.stft needs an int, and sfreq is usually a float
193
+ hop_length = int(self.sfreq // 2)
194
+ self.hop_length = hop_length
193
195
 
194
196
  if self.input_window_seconds < 1.0:
195
197
  warning_msg = (
@@ -181,6 +181,7 @@ class CTNet(EEGModuleMixin, nn.Module, license="mit"):
181
181
  drop_prob=self.att_positional_drop_prob,
182
182
  n_times=self.n_times,
183
183
  pool_size=self.pool_size_1,
184
+ sequence_length=self.sequence_length,
184
185
  )
185
186
 
186
187
  self.trans = _TransformerEncoder(
@@ -220,7 +221,7 @@ class CTNet(EEGModuleMixin, nn.Module, license="mit"):
220
221
  cnn = self.position(cnn)
221
222
  trans = self.trans(cnn)
222
223
  features = cnn + trans
223
- flatten_feature = self.flatten(features)
224
+ flatten_feature = self.flatten_drop_layer(features)
224
225
  out = self.final_layer(flatten_feature)
225
226
  return out
226
227
 
@@ -516,18 +517,23 @@ class _PositionalEncoding(nn.Module):
516
517
  length: int = 100,
517
518
  drop_prob: float = 0.1,
518
519
  pool_size: int = 8,
520
+ sequence_length: int | None = None,
519
521
  ):
520
522
  super().__init__()
521
523
  self.pool_size = pool_size
522
524
  self.n_times = n_times
523
525
 
524
- if int(n_times / (pool_size * pool_size)) > length:
526
+ # n_times / pool_size**2 is the sequence length only when both pooling
527
+ # sizes are equal; also cover the actual length (e.g. pool_size_2 <
528
+ # pool_size_1), so that the encoding is never shorter than the input
529
+ needed = max(int(n_times / (pool_size * pool_size)), sequence_length or 0)
530
+ if needed > length:
525
531
  warn(
526
532
  "the temporal dimensional is too long for this default length. "
527
533
  "The length parameter will be automatically adjusted to "
528
534
  "avoid inference issues."
529
535
  )
530
- length = int(n_times / (pool_size * pool_size))
536
+ length = needed
531
537
 
532
538
  self.dropout = nn.Dropout(drop_prob)
533
539
  self.encoding = nn.Parameter(torch.randn(1, length, emb_size))