Braindecode 1.6.1__tar.gz → 1.6.1.dev1014__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 (176) hide show
  1. {braindecode-1.6.1/braindecode.egg-info → braindecode-1.6.1.dev1014}/PKG-INFO +1 -1
  2. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/augmentation/base.py +19 -67
  3. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/augmentation/functional.py +30 -44
  4. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/__init__.py +0 -2
  5. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/base.py +0 -109
  6. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/eegneuralnet.py +1 -8
  7. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/functional/__init__.py +0 -8
  8. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/functional/functions.py +0 -159
  9. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/__init__.py +0 -6
  10. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/biot.py +10 -3
  11. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/brainmodule.py +54 -185
  12. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/eegitnet.py +12 -33
  13. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/eegsym.py +96 -72
  14. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/fbmsnet.py +5 -18
  15. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/medformer.py +22 -4
  16. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/msvtnet.py +3 -7
  17. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/sinc_shallow.py +2 -2
  18. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/summary.csv +60 -62
  19. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/util.py +0 -48
  20. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/modules/__init__.py +1 -6
  21. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/modules/activation.py +0 -34
  22. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/modules/blocks.py +25 -100
  23. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/modules/filter.py +19 -80
  24. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/modules/layers.py +0 -126
  25. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/preprocessing/mne_preprocess.py +12 -129
  26. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/training/scoring.py +1 -8
  27. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/util.py +1 -36
  28. braindecode-1.6.1.dev1014/braindecode/version.py +1 -0
  29. {braindecode-1.6.1 → braindecode-1.6.1.dev1014/braindecode.egg-info}/PKG-INFO +1 -1
  30. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode.egg-info/SOURCES.txt +0 -3
  31. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/api.rst +0 -7
  32. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/conf.py +0 -14
  33. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/models/models_table.rst +1 -4
  34. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/whats_new.rst +1 -102
  35. braindecode-1.6.1/braindecode/datasets/collate.py +0 -105
  36. braindecode-1.6.1/braindecode/models/mvpformer.py +0 -750
  37. braindecode-1.6.1/braindecode/models/steegformer.py +0 -654
  38. braindecode-1.6.1/braindecode/version.py +0 -1
  39. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/LICENSE.txt +0 -0
  40. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/MANIFEST.in +0 -0
  41. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/NOTICE.txt +0 -0
  42. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/README.rst +0 -0
  43. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/__init__.py +0 -0
  44. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/augmentation/__init__.py +0 -0
  45. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/augmentation/transforms.py +0 -0
  46. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/classifier.py +0 -0
  47. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/bbci.py +0 -0
  48. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/bcicomp.py +0 -0
  49. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/bids/__init__.py +0 -0
  50. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/bids/datasets.py +0 -0
  51. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/bids/format.py +0 -0
  52. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/bids/hub.py +0 -0
  53. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/bids/hub_format.py +0 -0
  54. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/bids/hub_io.py +0 -0
  55. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/bids/hub_validation.py +0 -0
  56. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/bids/iterable.py +0 -0
  57. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/chb_mit.py +0 -0
  58. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/mne.py +0 -0
  59. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/moabb.py +0 -0
  60. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/nmt.py +0 -0
  61. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/registry.py +0 -0
  62. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/siena.py +0 -0
  63. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  64. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/sleep_physionet.py +0 -0
  65. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/tuh.py +0 -0
  66. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/utils.py +0 -0
  67. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datasets/xy.py +0 -0
  68. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datautil/__init__.py +0 -0
  69. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datautil/channel_utils.py +0 -0
  70. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datautil/hub_formats.py +0 -0
  71. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datautil/serialization.py +0 -0
  72. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/datautil/util.py +0 -0
  73. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/functional/initialization.py +0 -0
  74. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/atcnet.py +0 -0
  75. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/attentionbasenet.py +0 -0
  76. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/attn_sleep.py +0 -0
  77. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/base.py +0 -0
  78. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/bendr.py +0 -0
  79. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/cbramod.py +0 -0
  80. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/codebrain.py +0 -0
  81. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/config.py +0 -0
  82. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/contrawr.py +0 -0
  83. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/ctnet.py +0 -0
  84. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/deep4.py +0 -0
  85. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/deepsleepnet.py +0 -0
  86. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/dgcnn.py +0 -0
  87. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/eegconformer.py +0 -0
  88. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/eegdino.py +0 -0
  89. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/eeginception_erp.py +0 -0
  90. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/eeginception_mi.py +0 -0
  91. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/eegminer.py +0 -0
  92. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/eegnet.py +0 -0
  93. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/eegnex.py +0 -0
  94. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/eegpt.py +0 -0
  95. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/eegsimpleconv.py +0 -0
  96. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/eegtcnet.py +0 -0
  97. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/emg2qwerty.py +0 -0
  98. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/fbcnet.py +0 -0
  99. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/fblightconvnet.py +0 -0
  100. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/hybrid.py +0 -0
  101. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/ifnet.py +0 -0
  102. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/interpolated.py +0 -0
  103. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/labram.py +0 -0
  104. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/luna.py +0 -0
  105. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/meta_neuromotor.py +0 -0
  106. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/patchedtransformer.py +0 -0
  107. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/reve.py +0 -0
  108. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/sccnet.py +0 -0
  109. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/shallow_fbcsp.py +0 -0
  110. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/signal_jepa.py +0 -0
  111. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
  112. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  113. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/sparcnet.py +0 -0
  114. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/sstdpn.py +0 -0
  115. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/syncnet.py +0 -0
  116. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/tcformer.py +0 -0
  117. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/tcn.py +0 -0
  118. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/tidnet.py +0 -0
  119. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/tsinception.py +0 -0
  120. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/models/usleep.py +0 -0
  121. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/modules/attention.py +0 -0
  122. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/modules/convolution.py +0 -0
  123. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/modules/interpolation.py +0 -0
  124. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/modules/linear.py +0 -0
  125. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/modules/parametrization.py +0 -0
  126. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/modules/stats.py +0 -0
  127. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/modules/util.py +0 -0
  128. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/modules/wrapper.py +0 -0
  129. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/preprocessing/__init__.py +0 -0
  130. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
  131. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/preprocessing/preprocess.py +0 -0
  132. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/preprocessing/util.py +0 -0
  133. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/preprocessing/windowers.py +0 -0
  134. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/regressor.py +0 -0
  135. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/samplers/__init__.py +0 -0
  136. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/samplers/base.py +0 -0
  137. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/samplers/ssl.py +0 -0
  138. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/training/__init__.py +0 -0
  139. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/training/callbacks.py +0 -0
  140. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/training/losses.py +0 -0
  141. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/visualization/__init__.py +0 -0
  142. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/visualization/attribution.py +0 -0
  143. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/visualization/confusion_matrices.py +0 -0
  144. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/visualization/frequency.py +0 -0
  145. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/visualization/metrics.py +0 -0
  146. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/visualization/sanity.py +0 -0
  147. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode/visualization/topology.py +0 -0
  148. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode.egg-info/dependency_links.txt +0 -0
  149. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode.egg-info/requires.txt +0 -0
  150. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/braindecode.egg-info/top_level.txt +0 -0
  151. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/Makefile +0 -0
  152. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/_templates/autosummary/class.rst +0 -0
  153. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  154. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/_templates/autosummary/function.rst +0 -0
  155. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  156. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/cite.rst +0 -0
  157. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/help.rst +0 -0
  158. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/index.rst +0 -0
  159. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/install/install.rst +0 -0
  160. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/install/install_pip.rst +0 -0
  161. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/install/install_source.rst +0 -0
  162. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/models/categorization/attention.rst +0 -0
  163. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/models/categorization/channel.rst +0 -0
  164. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/models/categorization/convolution.rst +0 -0
  165. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/models/categorization/filterbank.rst +0 -0
  166. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/models/categorization/gnn.rst +0 -0
  167. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/models/categorization/interpretable.rst +0 -0
  168. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/models/categorization/lbm.rst +0 -0
  169. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/models/categorization/recurrent.rst +0 -0
  170. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/models/categorization/spd.rst +0 -0
  171. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/models/models.rst +0 -0
  172. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/models/models_categorization.rst +0 -0
  173. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/models/models_visualization.rst +0 -0
  174. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/docs/sg_execution_times.rst +0 -0
  175. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/pyproject.toml +0 -0
  176. {braindecode-1.6.1 → braindecode-1.6.1.dev1014}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.6.1
3
+ Version: 1.6.1.dev1014
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>
@@ -105,15 +105,7 @@ class Transform(torch.nn.Module):
105
105
  mask = self._get_mask(out_X.shape[0], out_X.device)
106
106
  num_valid = mask.sum().long()
107
107
 
108
- if num_valid == out_X.shape[0]:
109
- # Fast path: every sample is augmented (e.g. ``probability=1.0``,
110
- # the common case). Operate on the whole batch and skip the boolean
111
- # gather/scatter (``out_X[mask]`` then ``out_X[mask] = ...``), which
112
- # would otherwise copy the batch twice.
113
- out_X, out_y = self.operation(
114
- out_X, out_y, **self.get_augmentation_params(out_X, out_y)
115
- )
116
- elif num_valid > 0:
108
+ if num_valid > 0:
117
109
  # Uses the mask to define the output
118
110
  out_X[mask, ...], tr_y = self.operation(
119
111
  out_X[mask, ...],
@@ -176,47 +168,23 @@ class Compose(Transform):
176
168
  return X, y
177
169
 
178
170
 
179
- class _AugmentationCollate:
180
- """Collate that applies a transform to each batch, with optional expansion.
181
-
182
- A picklable callable (so it works with ``num_workers > 0``, unlike a
183
- closure) that collates the batch once and then either augments it in place
184
- or grows it.
171
+ def _make_collateable(transform, device=None):
172
+ """Wraps a transform to make it collateable.
185
173
 
186
- Parameters
187
- ----------
188
- transform : Transform
189
- Transform applied to the collated ``(X, y)``.
190
- device : str | torch.device | None, optional
191
- Device the batch is moved to before transforming. Defaults to None.
192
- n_augmentation : int, optional
193
- ``0`` (default) applies the transform in place (batch size unchanged).
194
- ``> 0`` keeps the clean originals and appends ``n_augmentation``
195
- independently transformed copies, returning ``(X, y)`` of
196
- ``(1 + n_augmentation)`` times the original size.
174
+ with device control.
197
175
  """
198
176
 
199
- def __init__(self, transform, device=None, n_augmentation=0):
200
- self.transform = transform
201
- self.device = device
202
- self.n_augmentation = n_augmentation
203
-
204
- def __call__(self, batch):
205
- collated = default_collate(batch)
206
- X, y = collated[:2]
207
- if self.device is not None:
208
- X = X.to(self.device)
209
- y = y.to(self.device)
210
- if self.n_augmentation == 0:
211
- return (*self.transform(X, y), *collated[2:])
212
- # Fixed expansion: keep the clean originals, then append
213
- # ``n_augmentation`` independently transformed copies.
214
- xs, ys = [X], [y]
215
- for _ in range(self.n_augmentation):
216
- aug_X, aug_y = self.transform(X, y)
217
- xs.append(aug_X)
218
- ys.append(aug_y)
219
- return torch.cat(xs), torch.cat(ys)
177
+ def _collate_fn(batch):
178
+ collated_batch = default_collate(batch)
179
+ X, y = collated_batch[:2]
180
+
181
+ if device is not None:
182
+ X = X.to(device)
183
+ y = y.to(device)
184
+
185
+ return (*transform(X, y), *collated_batch[2:])
186
+
187
+ return _collate_fn
220
188
 
221
189
 
222
190
  class AugmentedDataLoader(DataLoader):
@@ -230,44 +198,28 @@ class AugmentedDataLoader(DataLoader):
230
198
  Transform or sequence of Transform to be applied to each batch.
231
199
  device : str | torch.device | None, optional
232
200
  Device on which to transform the data. Defaults to None.
233
- n_augmentation : int, optional
234
- Number of augmented copies to append to each batch (fixed expansion).
235
- When ``0`` (default) the transforms are applied in place and the batch
236
- keeps its size (stochastic-per-epoch augmentation, backwards-compatible).
237
- When ``> 0`` each batch becomes ``(1 + n_augmentation)`` times larger:
238
- the clean originals are kept and ``n_augmentation`` independently
239
- transformed copies are appended. This expresses augmentations defined as
240
- a fixed set-expansion (e.g. the EEG-Inception MI 6x training set,
241
- ``n_augmentation=5``). In this mode batches are returned as ``(X, y)``.
242
201
  **kwargs : dict, optional
243
202
  keyword arguments to pass to standard DataLoader class.
244
203
  """
245
204
 
246
- def __init__(
247
- self, dataset, transforms=None, device=None, n_augmentation=0, **kwargs
248
- ):
205
+ def __init__(self, dataset, transforms=None, device=None, **kwargs):
249
206
  if "collate_fn" in kwargs:
250
207
  raise ValueError(
251
208
  "collate_fn cannot be used in this context because it is used "
252
209
  "to pass transform"
253
210
  )
254
- if n_augmentation < 0:
255
- raise ValueError("n_augmentation must be a non-negative integer.")
256
211
  if transforms is None or (
257
212
  isinstance(transforms, list) and len(transforms) == 0
258
213
  ):
259
- transform = IdentityTransform()
214
+ self.collated_tr = _make_collateable(IdentityTransform(), device=device)
260
215
  elif isinstance(transforms, (Transform, nn.Module)):
261
- transform = transforms
216
+ self.collated_tr = _make_collateable(transforms, device=device)
262
217
  elif isinstance(transforms, list):
263
- transform = Compose(transforms)
218
+ self.collated_tr = _make_collateable(Compose(transforms), device=device)
264
219
  else:
265
220
  raise TypeError(
266
221
  "transforms can be either a Transform object "
267
222
  "or a list of Transform objects."
268
223
  )
269
224
 
270
- self.collated_tr = _AugmentationCollate(
271
- transform, device=device, n_augmentation=n_augmentation
272
- )
273
225
  super().__init__(dataset, collate_fn=self.collated_tr, **kwargs)
@@ -18,7 +18,7 @@ from mne.filter import notch_filter
18
18
  from scipy.interpolate import Rbf
19
19
  from sklearn.utils import check_random_state
20
20
  from torch.fft import fft, ifft
21
- from torch.nn.functional import pad
21
+ from torch.nn.functional import one_hot, pad
22
22
 
23
23
 
24
24
  def identity(X: torch.Tensor, y: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
@@ -253,34 +253,25 @@ def channels_dropout(
253
253
  return X * mask.unsqueeze(-1), y
254
254
 
255
255
 
256
- def _make_channel_permutation(
256
+ def _make_permutation_matrix(
257
257
  X: torch.Tensor, mask: torch.Tensor, random_state: int | np.random.Generator | None
258
258
  ) -> torch.Tensor:
259
- """Per-sample channel permutation that shuffles only the masked channels.
260
-
261
- Returns a ``(batch, n_channels)`` index permutation: output channel ``i`` is
262
- taken from input channel ``perm[b, i]``. Masked channels are permuted among
263
- their own positions; unmasked channels keep their place.
264
-
265
- The per-sample ``rng.permutation`` is kept (rather than a vectorized random
266
- draw) so the output is bit-for-bit identical to the previous one-hot/matmul
267
- implementation — vectorizing the draw would change seeded results. The win
268
- is downstream: the caller gathers with this index instead of building
269
- ``(batch, n_channels, n_channels)`` one-hot matrices and a matmul.
270
- """
271
259
  rng = check_random_state(random_state)
272
260
  batch_size, n_channels, _ = X.shape
273
- hard_mask = mask.round().bool()
274
- channels = torch.arange(n_channels, device=X.device)
275
- perm = channels.repeat(batch_size, 1)
276
- for b in range(batch_size):
277
- channels_to_shuffle = channels[hard_mask[b]]
278
- perm[b, channels_to_shuffle] = torch.tensor(
279
- rng.permutation(channels_to_shuffle.cpu()),
280
- device=X.device,
281
- dtype=perm.dtype,
261
+ hard_mask = mask.round()
262
+ batch_permutations = torch.empty(
263
+ batch_size, n_channels, n_channels, device=X.device
264
+ )
265
+ for b, mask in enumerate(hard_mask):
266
+ channels_to_shuffle = torch.arange(n_channels, device=X.device)
267
+ channels_to_shuffle = channels_to_shuffle[mask.bool()]
268
+ reordered_channels = torch.tensor(
269
+ rng.permutation(channels_to_shuffle.cpu()), device=X.device
282
270
  )
283
- return perm
271
+ channels_permutation = torch.arange(n_channels, device=X.device)
272
+ channels_permutation[channels_to_shuffle] = reordered_channels
273
+ batch_permutations[b, ...] = one_hot(channels_permutation)
274
+ return batch_permutations
284
275
 
285
276
 
286
277
  def channels_shuffle(
@@ -323,11 +314,8 @@ def channels_shuffle(
323
314
  if p_shuffle == 0:
324
315
  return X, y
325
316
  mask = _pick_channels_randomly(X, 1 - p_shuffle, random_state)
326
- perm = _make_channel_permutation(X, mask, random_state)
327
- # Gather channels (output[b, i] = X[b, perm[b, i]]) instead of building
328
- # one-hot permutation matrices and a (batch, C, C) @ (batch, C, T) matmul.
329
- perm = perm.unsqueeze(-1).expand(-1, -1, X.shape[-1])
330
- return torch.gather(X, 1, perm), y
317
+ batch_permutations = _make_permutation_matrix(X, mask, random_state)
318
+ return torch.matmul(batch_permutations, X), y
331
319
 
332
320
 
333
321
  def gaussian_noise(
@@ -1200,21 +1188,19 @@ def mask_encoding(
1200
1188
  32 (2024): 875-886.
1201
1189
  """
1202
1190
 
1203
- # All channels are zeroed at the same time positions, so build a single
1204
- # (batch, n_times) time-mask and broadcast it over channels, vectorized
1205
- # (no Python loop over batch * n_segments).
1206
- device = X.device
1207
- batch_indices = torch.arange(X.shape[0], device=device).repeat_interleave(
1208
- n_segments * segment_length
1209
- )
1210
- seg_indices = (
1211
- time_start.flatten().to(device)[:, None]
1212
- + torch.arange(segment_length, device=device)
1213
- ).flatten()
1214
- time_mask = torch.zeros(X.shape[0], X.shape[-1], dtype=torch.bool, device=device)
1215
- time_mask[batch_indices, seg_indices] = True
1216
-
1217
- return X.masked_fill(time_mask.unsqueeze(1), 0), y
1191
+ batch_indices = torch.arange(X.shape[0]).repeat_interleave(n_segments)
1192
+ start_indices = time_start.flatten()
1193
+ mask_indices = start_indices[:, None] + torch.arange(segment_length)
1194
+
1195
+ # Create a boolean mask with the same shape as X
1196
+ mask = torch.zeros_like(X, dtype=torch.bool)
1197
+ for batch_index, grouped_mask_indices in zip(batch_indices, mask_indices):
1198
+ mask[batch_index, :, grouped_mask_indices] = True
1199
+
1200
+ # Apply the mask to set the values to 0
1201
+ X[mask] = 0
1202
+
1203
+ return X, y # Return the masked tensor and labels
1218
1204
 
1219
1205
 
1220
1206
  def channels_rereference(
@@ -10,7 +10,6 @@ from .base import (
10
10
  from .bcicomp import BCICompetitionIVDataset4
11
11
  from .bids import BIDSDataset, BIDSEpochsDataset
12
12
  from .chb_mit import CHBMIT
13
- from .collate import pad_channels_collate
14
13
  from .mne import create_from_mne_epochs, create_from_mne_raw
15
14
  from .moabb import BNCI2014_001, HGD, MOABBDataset
16
15
  from .nmt import NMT
@@ -43,5 +42,4 @@ __all__ = [
43
42
  "SleepPhysionetChallenge2018",
44
43
  "create_from_X_y",
45
44
  "BCICompetitionIVDataset4",
46
- "pad_channels_collate",
47
45
  ]
@@ -192,31 +192,6 @@ def _channel_info(mne_obj):
192
192
  return n_ch, type_str, sfreq
193
193
 
194
194
 
195
- def _compute_ch_pos(info, targets_from):
196
- """Return ``(n_ch, 3)`` float32 electrode positions aligned to ``X``'s rows.
197
-
198
- Positions are the MNE head-frame coordinates ``info["chs"][i]["loc"][:3]``
199
- (meters) -- the same representation braindecode models already consume (see
200
- e.g. ``signal_jepa``/``REVE``). When ``targets_from != "metadata"`` the
201
- window's misc channels are dropped from ``X`` in ``__getitem__``, so the
202
- matching misc rows are dropped here too. Emits a one-time ``UserWarning`` if
203
- no channel carries a real position (no montage set).
204
- """
205
- pos = np.asarray([ch["loc"][:3] for ch in info["chs"]], dtype="float32")
206
- if targets_from != "metadata":
207
- misc_mask = np.asarray(info.get_channel_types()) == "misc"
208
- pos = pos[~misc_mask]
209
- has_pos = np.isfinite(pos).all(axis=1) & np.any(pos != 0, axis=1)
210
- if pos.size and not has_pos.any():
211
- warnings.warn(
212
- "Returning channel positions but no montage is set: all positions "
213
- "are zero/non-finite. Call ``raw.set_montage(...)`` (or set a "
214
- "montage during preprocessing) before enabling ``return_ch_pos``.",
215
- UserWarning,
216
- )
217
- return pos
218
-
219
-
220
195
  def _window_info(crop_inds, sfreq):
221
196
  """Extract window size from crop indices.
222
197
 
@@ -473,10 +448,6 @@ class RecordDataset(Dataset[tuple[np.ndarray, int | str, tuple[int, int, int]]])
473
448
  ):
474
449
  self._description = _create_description(description)
475
450
  self.transform = transform
476
- # Opt-in: when True, ``__getitem__`` appends channel positions (n_ch, 3).
477
- # Default off keeps the public ``(X, y, crop_inds)`` contract intact.
478
- self.return_ch_pos = False
479
- self._ch_pos = None
480
451
 
481
452
  @abstractmethod
482
453
  def __len__(self) -> int:
@@ -779,20 +750,6 @@ class EEGWindowsDataset(_ZarrMixin, RecordDataset):
779
750
  @raw.setter
780
751
  def raw(self, value):
781
752
  self._raw = value
782
- self._ch_pos = None # invalidate cached positions
783
-
784
- @property
785
- def ch_pos(self):
786
- """Electrode positions ``(n_ch, 3)`` (x, y, z) aligned to ``X``'s channels.
787
-
788
- Cached MNE head-frame coordinates in meters. Rows match the channels
789
- returned by :meth:`__getitem__` (misc target channels excluded when
790
- ``targets_from="channels"``). All-zero/NaN when no montage is set.
791
- """
792
- if self._ch_pos is None:
793
- info = self._raw.info if self._raw is not None else self._make_mne_info()
794
- self._ch_pos = _compute_ch_pos(info, self.targets_from)
795
- return self._ch_pos
796
753
 
797
754
  def __getitem__(self, index: int):
798
755
  """Get a window and its target.
@@ -836,8 +793,6 @@ class EEGWindowsDataset(_ZarrMixin, RecordDataset):
836
793
  y = X[misc_mask, :]
837
794
  y = y.copy()
838
795
  X = X[~misc_mask, :]
839
- if self.return_ch_pos:
840
- return X, y, crop_inds, self.ch_pos
841
796
  return X, y, crop_inds
842
797
 
843
798
  def __len__(self):
@@ -1061,24 +1016,6 @@ class WindowsDataset(_ZarrMixin, RecordDataset):
1061
1016
  @windows.setter
1062
1017
  def windows(self, value):
1063
1018
  self._windows = value
1064
- self._ch_pos = None # invalidate cached positions
1065
-
1066
- @property
1067
- def ch_pos(self):
1068
- """Electrode positions ``(n_ch, 3)`` (x, y, z) aligned to ``X``'s channels.
1069
-
1070
- Cached MNE head-frame coordinates in meters. Rows match the channels
1071
- returned by :meth:`__getitem__` (misc target channels excluded when
1072
- ``targets_from="channels"``). All-zero/NaN when no montage is set.
1073
- """
1074
- if self._ch_pos is None:
1075
- info = (
1076
- self._windows.info
1077
- if self._windows is not None
1078
- else self._make_mne_info()
1079
- )
1080
- self._ch_pos = _compute_ch_pos(info, self.targets_from)
1081
- return self._ch_pos
1082
1019
 
1083
1020
  @staticmethod
1084
1021
  def _can_use_fast_get_epoch_from_raw(epochs: mne.BaseEpochs) -> bool:
@@ -1131,8 +1068,6 @@ class WindowsDataset(_ZarrMixin, RecordDataset):
1131
1068
  # necessary to cast as list to get list of three tensors from batch,
1132
1069
  # otherwise get single 2d-tensor...
1133
1070
  crop_inds = self.crop_inds[index].tolist()
1134
- if self.return_ch_pos:
1135
- return X, y, crop_inds, self.ch_pos
1136
1071
  return X, y, crop_inds
1137
1072
 
1138
1073
  def __len__(self) -> int:
@@ -1523,50 +1458,6 @@ class BaseConcatDataset(ConcatDataset, HubDatasetMixin, Generic[T]):
1523
1458
  )
1524
1459
  return self
1525
1460
 
1526
- def set_return_ch_pos(self, value: bool = True) -> "BaseConcatDataset":
1527
- """Toggle returning electrode positions from every subdataset.
1528
-
1529
- When enabled, each windowed subdataset's ``__getitem__`` appends a
1530
- ``(n_ch, 3)`` array of electrode positions (x, y, z), so a batch yields
1531
- ``(X, y, crop_inds, ch_pos)``. Heterogeneous (variable-channel)
1532
- collections additionally need
1533
- :func:`braindecode.datasets.pad_channels_collate` as the DataLoader
1534
- ``collate_fn``. Default-off: leaves the ``(X, y, crop_inds)`` contract
1535
- untouched.
1536
-
1537
- Parameters
1538
- ----------
1539
- value : bool
1540
- Whether to return channel positions (default ``True``).
1541
-
1542
- Returns
1543
- -------
1544
- self : BaseConcatDataset
1545
- """
1546
- for ds in self.datasets:
1547
- ds.return_ch_pos = value
1548
- return self
1549
-
1550
- @property
1551
- def ch_pos(self):
1552
- """Electrode positions ``(n_ch, 3)`` from the first recording.
1553
-
1554
- Convenience accessor mirroring how the repr reports channel info "from
1555
- first recording". For per-sample positions in a heterogeneous
1556
- collection, enable :meth:`set_return_ch_pos` and read them from the
1557
- batch instead.
1558
- """
1559
- if not self.datasets:
1560
- raise ValueError("Empty BaseConcatDataset has no channel positions.")
1561
- first = self.datasets[0]
1562
- if not hasattr(first, "ch_pos"):
1563
- raise AttributeError(
1564
- f"{type(first).__name__} does not expose channel positions; "
1565
- "ch_pos is available on windowed datasets (EEGWindowsDataset / "
1566
- "WindowsDataset)."
1567
- )
1568
- return first.ch_pos
1569
-
1570
1461
  def _outdated_save(self, path, overwrite=False):
1571
1462
  """This is a copy of the old saving function, that had inconsistent.
1572
1463
 
@@ -134,14 +134,7 @@ class _EEGNeuralNet(NeuralNet, abc.ABC):
134
134
  i_window_in_trials = []
135
135
  i_window_stops = []
136
136
  window_ys = []
137
- for batch in self.get_iterator(dataset, drop_index=False):
138
- if len(batch) > 3:
139
- raise ValueError(
140
- "Cropped prediction does not support channel positions; "
141
- "disable return_ch_pos (set_return_ch_pos(False)) for cropped "
142
- "evaluation."
143
- )
144
- X, y, i = batch[0], batch[1], batch[2]
137
+ for X, y, i in self.get_iterator(dataset, drop_index=False):
145
138
  i_window_in_trials.append(i[0].cpu().numpy())
146
139
  i_window_stops.append(i[2].cpu().numpy())
147
140
  with torch.no_grad():
@@ -1,30 +1,22 @@
1
1
  from .functions import (
2
2
  _get_gaussian_kernel1d,
3
- daubechies_filters,
4
3
  drop_path,
5
- dwt_max_level,
6
4
  hilbert_freq,
7
5
  identity,
8
6
  plv_time,
9
7
  safe_log,
10
- sinusoidal_positional_encoding,
11
8
  square,
12
- wavelet_decomposition,
13
9
  )
14
10
  from .initialization import glorot_weight_zero_bias, rescale_parameter
15
11
 
16
12
  __all__ = [
17
13
  "_get_gaussian_kernel1d",
18
- "daubechies_filters",
19
14
  "drop_path",
20
- "dwt_max_level",
21
15
  "hilbert_freq",
22
16
  "identity",
23
17
  "plv_time",
24
18
  "safe_log",
25
- "sinusoidal_positional_encoding",
26
19
  "square",
27
- "wavelet_decomposition",
28
20
  "glorot_weight_zero_bias",
29
21
  "rescale_parameter",
30
22
  ]
@@ -1,13 +1,7 @@
1
1
  # Authors: Robin Schirrmeister <robintibor@gmail.com>
2
- # Bruno Aristimunha <b.aristimunha@gmail.com>
3
2
  #
4
3
  # License: BSD (3-clause)
5
4
 
6
- from __future__ import annotations
7
-
8
- import math
9
-
10
- import numpy as np
11
5
  import torch
12
6
  import torch.nn.functional as F
13
7
 
@@ -255,156 +249,3 @@ def plv_time(x, forward_fourier=True, epsilon: float = 1e-6):
255
249
  )
256
250
 
257
251
  return plv_matrix
258
-
259
-
260
- def daubechies_filters(n_vanishing: int) -> torch.Tensor:
261
- r"""Daubechies ``db<n_vanishing>`` wavelet decomposition filters.
262
-
263
- Computes the orthogonal decomposition (analysis) low-pass and high-pass
264
- filters by spectral factorisation of the Daubechies half-band (Bezout)
265
- polynomial, so no external wavelet library (PyWavelets, ptwt) is required.
266
- For ``n_vanishing=4`` the result equals ``pywt.Wavelet("db4").dec_lo`` /
267
- ``.dec_hi`` to machine precision (bit-identical once cast to ``float32``).
268
-
269
- Parameters
270
- ----------
271
- n_vanishing : int
272
- Number of vanishing moments (the ``N`` in ``dbN``). The filters have
273
- ``2 * n_vanishing`` taps.
274
-
275
- Returns
276
- -------
277
- torch.Tensor
278
- Shape ``(2, 2 * n_vanishing)`` whose rows are the low-pass and high-pass
279
- decomposition filters ``[dec_lo, dec_hi]``.
280
-
281
- Notes
282
- -----
283
- Half-band polynomial :math:`P(y) = \sum_{k=0}^{N-1} \binom{N-1+k}{k} y^k`
284
- with :math:`y = (1 - \cos\omega)/2`. Its roots are mapped to the
285
- minimum-phase (:math:`|z| < 1`) roots of :math:`z^2 - 2(1-2y)z + 1`; the
286
- analysis low-pass is :math:`H(z) = (1+z)^N` times that spectral factor
287
- (normalised so it sums to :math:`\sqrt 2`), and the high-pass is the
288
- quadrature mirror :math:`g_k = (-1)^{k+1} h_{L-1-k}`.
289
- """
290
- n = n_vanishing
291
- poly = np.array([math.comb(n - 1 + k, k) for k in range(n)], dtype=float)
292
- z_inside = []
293
- for y in np.roots(poly[::-1]):
294
- b = -2.0 * (1.0 - 2.0 * y)
295
- disc = np.sqrt(b * b - 4.0 + 0j)
296
- r1, r2 = (-b + disc) / 2.0, (-b - disc) / 2.0
297
- z_inside.append(r1 if abs(r1) < 1.0 else r2)
298
- low = np.poly([-1.0] * n + z_inside).real
299
- low *= math.sqrt(2.0) / low.sum()
300
- dec_lo = low[::-1] # pywt stores the time-reversed decomposition low-pass
301
- length = len(dec_lo)
302
- dec_hi = np.array(
303
- [(-1.0) ** (k + 1) * dec_lo[length - 1 - k] for k in range(length)]
304
- )
305
- return torch.tensor(np.stack([dec_lo, dec_hi]), dtype=torch.float32)
306
-
307
-
308
- def dwt_max_level(n_times: int, filter_len: int) -> int:
309
- """Maximum number of discrete wavelet decomposition levels.
310
-
311
- Matches ``pywt.dwt_max_level`` = ``floor(log2(n_times / (filter_len - 1)))``.
312
-
313
- Parameters
314
- ----------
315
- n_times : int
316
- Length of the signal.
317
- filter_len : int
318
- Number of wavelet filter taps.
319
-
320
- Returns
321
- -------
322
- int
323
- Maximum decomposition level (``0`` if the signal is shorter than the
324
- filter).
325
- """
326
- if n_times < filter_len:
327
- return 0
328
- return max(0, int(math.floor(math.log2(n_times / (filter_len - 1)))))
329
-
330
-
331
- def wavelet_decomposition(
332
- x: torch.Tensor, filters: torch.Tensor, n_levels: int | None = None
333
- ) -> torch.Tensor:
334
- r"""Multilevel discrete wavelet decomposition with periodic boundary.
335
-
336
- A cascade of strided convolutions with circular padding, bit-identical to
337
- ``pywt`` / ``ptwt`` ``wavedec(mode="periodic")``. The approximation and
338
- detail coefficients of every level are concatenated along the last axis as
339
- ``[cA_n, cD_n, cD_{n-1}, ..., cD_1]``.
340
-
341
- Parameters
342
- ----------
343
- x : torch.Tensor
344
- Input signal of shape ``(..., n_times)``.
345
- filters : torch.Tensor
346
- Decomposition filters of shape ``(2, filter_len)`` =
347
- ``[low-pass, high-pass]`` (e.g. from :func:`daubechies_filters`).
348
- n_levels : int, optional
349
- Number of decomposition levels. Defaults to the maximum
350
- (:func:`dwt_max_level`).
351
-
352
- Returns
353
- -------
354
- torch.Tensor
355
- Concatenated coefficients of shape ``(..., dwt_len)``.
356
- """
357
- filter_len = filters.shape[-1]
358
- if n_levels is None:
359
- n_levels = dwt_max_level(x.shape[-1], filter_len)
360
- leading = x.shape[:-1]
361
- approx = x.reshape(-1, x.shape[-1])
362
- # Flip the taps so conv1d (cross-correlation) realises the wavelet convolution.
363
- weight = filters.flip(-1).unsqueeze(1).to(device=approx.device, dtype=approx.dtype)
364
- details = []
365
- for _ in range(n_levels):
366
- pad = (2 * filter_len - 3) // 2
367
- padded = F.pad(
368
- approx.unsqueeze(1), (pad, pad + approx.shape[-1] % 2), mode="circular"
369
- )
370
- approx, detail = F.conv1d(padded, weight, stride=2).unbind(dim=1)
371
- details.append(detail)
372
- out = torch.cat([approx, *reversed(details)], dim=-1)
373
- return out.reshape(*leading, -1)
374
-
375
-
376
- def sinusoidal_positional_encoding(n_positions: int, dim: int) -> torch.Tensor:
377
- r"""Fixed sine/cosine positional-encoding table of shape ``(n_positions, dim)``.
378
-
379
- The standard encoding of Vaswani et al. (2017): for position :math:`p` and
380
- channel :math:`i`, :math:`pe[p, 2i] = \sin(p / 10000^{2i/d})` and
381
- :math:`pe[p, 2i+1] = \cos(p / 10000^{2i/d})`. PyTorch ships no sinusoidal
382
- encoding (``nn.Embedding`` is a *learned* lookup), so braindecode models that
383
- need one share this primitive instead of re-deriving it. An odd ``dim`` is
384
- computed on the next even width and truncated, reproducing the per-model
385
- wrappers (e.g. :class:`~braindecode.models.medformer` odd-``d_model``).
386
-
387
- Parameters
388
- ----------
389
- n_positions : int
390
- Number of positions (sequence length) to encode.
391
- dim : int
392
- Embedding dimension of each position.
393
-
394
- Returns
395
- -------
396
- torch.Tensor
397
- ``(n_positions, dim)`` float table; callers add their own batch axis,
398
- dropout, or offset.
399
- """
400
- dim_even = dim + (dim % 2)
401
- position = torch.arange(n_positions).unsqueeze(1).float()
402
- div_term = torch.exp(
403
- torch.arange(0, dim_even, 2).float() * (-math.log(10000.0) / dim_even)
404
- )
405
- pe = torch.zeros(n_positions, dim_even)
406
- pe[:, 0::2] = torch.sin(position * div_term)
407
- pe[:, 1::2] = torch.cos(position * div_term)
408
- # ``.contiguous()`` so an odd-``dim`` truncation owns tight storage -- a
409
- # non-contiguous view over the padded width breaks safetensors buffer saving.
410
- return pe[:, :dim].contiguous()
@@ -38,7 +38,6 @@ from .luna import LUNA
38
38
  from .medformer import MEDFormer
39
39
  from .meta_neuromotor import MetaNeuromotorHand
40
40
  from .msvtnet import MSVTNet
41
- from .mvpformer import MVPFormer
42
41
  from .patchedtransformer import PBT
43
42
  from .reve import REVE
44
43
  from .sccnet import SCCNet
@@ -55,7 +54,6 @@ from .sleep_stager_blanco_2020 import SleepStagerBlanco2020
55
54
  from .sleep_stager_chambon_2018 import SleepStagerChambon2018
56
55
  from .sparcnet import SPARCNet
57
56
  from .sstdpn import SSTDPN
58
- from .steegformer import STEEGFormer
59
57
  from .syncnet import SyncNet
60
58
  from .tcformer import TCFormer
61
59
  from .tcn import BDTCN, TCN
@@ -67,7 +65,6 @@ from .util import (
67
65
  build_model_config,
68
66
  extract_channel_locations_from_chs_info,
69
67
  models_mandatory_parameters,
70
- positions_from_chs_info,
71
68
  )
72
69
 
73
70
  # Call this last in order to make sure the dataset list is populated with
@@ -117,10 +114,8 @@ __all__ = [
117
114
  "Labram",
118
115
  "LUNA",
119
116
  "extract_channel_locations_from_chs_info",
120
- "positions_from_chs_info",
121
117
  "MEDFormer",
122
118
  "MSVTNet",
123
- "MVPFormer",
124
119
  "PBT",
125
120
  "REVE",
126
121
  "SCCNet",
@@ -134,7 +129,6 @@ __all__ = [
134
129
  "SleepStagerBlanco2020",
135
130
  "SleepStagerChambon2018",
136
131
  "SPARCNet",
137
- "STEEGFormer",
138
132
  "SyncNet",
139
133
  "BDTCN",
140
134
  "TCFormer",