braindecode 1.6.1.dev1065__tar.gz → 1.6.1.dev1073__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 (175) hide show
  1. {braindecode-1.6.1.dev1065/braindecode.egg-info → braindecode-1.6.1.dev1073}/PKG-INFO +1 -1
  2. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/augmentation/base.py +67 -19
  3. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/augmentation/functional.py +44 -30
  4. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/bids/hub.py +41 -1
  5. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/__init__.py +2 -0
  6. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/eegitnet.py +33 -12
  7. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/eegsym.py +9 -0
  8. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/msvtnet.py +7 -3
  9. braindecode-1.6.1.dev1073/braindecode/models/steegformer.py +660 -0
  10. braindecode-1.6.1.dev1073/braindecode/models/summary.csv +61 -0
  11. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/util.py +1 -0
  12. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/modules/blocks.py +100 -25
  13. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/modules/filter.py +8 -5
  14. braindecode-1.6.1.dev1073/braindecode/version.py +1 -0
  15. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073/braindecode.egg-info}/PKG-INFO +1 -1
  16. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode.egg-info/SOURCES.txt +1 -0
  17. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/api.rst +3 -0
  18. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/models/models_table.rst +4 -2
  19. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/whats_new.rst +45 -0
  20. braindecode-1.6.1.dev1065/braindecode/models/summary.csv +0 -60
  21. braindecode-1.6.1.dev1065/braindecode/version.py +0 -1
  22. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/LICENSE.txt +0 -0
  23. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/MANIFEST.in +0 -0
  24. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/NOTICE.txt +0 -0
  25. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/README.rst +0 -0
  26. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/__init__.py +0 -0
  27. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/augmentation/__init__.py +0 -0
  28. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/augmentation/transforms.py +0 -0
  29. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/classifier.py +0 -0
  30. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/__init__.py +0 -0
  31. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/base.py +0 -0
  32. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/bbci.py +0 -0
  33. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/bcicomp.py +0 -0
  34. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/bids/__init__.py +0 -0
  35. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/bids/datasets.py +0 -0
  36. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/bids/format.py +0 -0
  37. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/bids/hub_format.py +0 -0
  38. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/bids/hub_io.py +0 -0
  39. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/bids/hub_validation.py +0 -0
  40. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/bids/iterable.py +0 -0
  41. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/chb_mit.py +0 -0
  42. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/mne.py +0 -0
  43. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/moabb.py +0 -0
  44. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/nmt.py +0 -0
  45. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/registry.py +0 -0
  46. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/siena.py +0 -0
  47. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  48. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/sleep_physionet.py +0 -0
  49. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/tuh.py +0 -0
  50. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/utils.py +0 -0
  51. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datasets/xy.py +0 -0
  52. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datautil/__init__.py +0 -0
  53. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datautil/channel_utils.py +0 -0
  54. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datautil/hub_formats.py +0 -0
  55. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datautil/serialization.py +0 -0
  56. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/datautil/util.py +0 -0
  57. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/eegneuralnet.py +0 -0
  58. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/functional/__init__.py +0 -0
  59. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/functional/functions.py +0 -0
  60. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/functional/initialization.py +0 -0
  61. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/atcnet.py +0 -0
  62. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/attentionbasenet.py +0 -0
  63. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/attn_sleep.py +0 -0
  64. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/base.py +0 -0
  65. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/bendr.py +0 -0
  66. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/biot.py +0 -0
  67. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/brainmodule.py +0 -0
  68. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/cbramod.py +0 -0
  69. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/codebrain.py +0 -0
  70. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/config.py +0 -0
  71. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/contrawr.py +0 -0
  72. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/ctnet.py +0 -0
  73. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/deep4.py +0 -0
  74. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/deepsleepnet.py +0 -0
  75. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/dgcnn.py +0 -0
  76. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/eegconformer.py +0 -0
  77. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/eegdino.py +0 -0
  78. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/eeginception_erp.py +0 -0
  79. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/eeginception_mi.py +0 -0
  80. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/eegminer.py +0 -0
  81. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/eegnet.py +0 -0
  82. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/eegnex.py +0 -0
  83. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/eegpt.py +0 -0
  84. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/eegsimpleconv.py +0 -0
  85. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/eegtcnet.py +0 -0
  86. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/emg2qwerty.py +0 -0
  87. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/fbcnet.py +0 -0
  88. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/fblightconvnet.py +0 -0
  89. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/fbmsnet.py +0 -0
  90. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/hybrid.py +0 -0
  91. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/ifnet.py +0 -0
  92. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/interpolated.py +0 -0
  93. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/labram.py +0 -0
  94. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/luna.py +0 -0
  95. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/medformer.py +0 -0
  96. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/meta_neuromotor.py +0 -0
  97. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/patchedtransformer.py +0 -0
  98. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/reve.py +0 -0
  99. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/sccnet.py +0 -0
  100. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/shallow_fbcsp.py +0 -0
  101. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/signal_jepa.py +0 -0
  102. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/sinc_shallow.py +0 -0
  103. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
  104. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  105. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/sparcnet.py +0 -0
  106. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/sstdpn.py +0 -0
  107. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/syncnet.py +0 -0
  108. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/tcformer.py +0 -0
  109. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/tcn.py +0 -0
  110. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/tidnet.py +0 -0
  111. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/tsinception.py +0 -0
  112. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/models/usleep.py +0 -0
  113. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/modules/__init__.py +0 -0
  114. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/modules/activation.py +0 -0
  115. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/modules/attention.py +0 -0
  116. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/modules/convolution.py +0 -0
  117. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/modules/interpolation.py +0 -0
  118. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/modules/layers.py +0 -0
  119. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/modules/linear.py +0 -0
  120. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/modules/parametrization.py +0 -0
  121. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/modules/stats.py +0 -0
  122. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/modules/util.py +0 -0
  123. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/modules/wrapper.py +0 -0
  124. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/preprocessing/__init__.py +0 -0
  125. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
  126. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/preprocessing/mne_preprocess.py +0 -0
  127. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/preprocessing/preprocess.py +0 -0
  128. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/preprocessing/util.py +0 -0
  129. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/preprocessing/windowers.py +0 -0
  130. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/regressor.py +0 -0
  131. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/samplers/__init__.py +0 -0
  132. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/samplers/base.py +0 -0
  133. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/samplers/ssl.py +0 -0
  134. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/training/__init__.py +0 -0
  135. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/training/callbacks.py +0 -0
  136. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/training/losses.py +0 -0
  137. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/training/scoring.py +0 -0
  138. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/util.py +0 -0
  139. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/visualization/__init__.py +0 -0
  140. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/visualization/attribution.py +0 -0
  141. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/visualization/confusion_matrices.py +0 -0
  142. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/visualization/frequency.py +0 -0
  143. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/visualization/metrics.py +0 -0
  144. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/visualization/sanity.py +0 -0
  145. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode/visualization/topology.py +0 -0
  146. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode.egg-info/dependency_links.txt +0 -0
  147. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode.egg-info/requires.txt +0 -0
  148. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/braindecode.egg-info/top_level.txt +0 -0
  149. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/Makefile +0 -0
  150. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/_templates/autosummary/class.rst +0 -0
  151. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  152. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/_templates/autosummary/function.rst +0 -0
  153. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  154. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/cite.rst +0 -0
  155. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/conf.py +0 -0
  156. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/help.rst +0 -0
  157. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/index.rst +0 -0
  158. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/install/install.rst +0 -0
  159. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/install/install_pip.rst +0 -0
  160. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/install/install_source.rst +0 -0
  161. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/models/categorization/attention.rst +0 -0
  162. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/models/categorization/channel.rst +0 -0
  163. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/models/categorization/convolution.rst +0 -0
  164. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/models/categorization/filterbank.rst +0 -0
  165. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/models/categorization/gnn.rst +0 -0
  166. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/models/categorization/interpretable.rst +0 -0
  167. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/models/categorization/lbm.rst +0 -0
  168. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/models/categorization/recurrent.rst +0 -0
  169. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/models/categorization/spd.rst +0 -0
  170. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/models/models.rst +0 -0
  171. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/models/models_categorization.rst +0 -0
  172. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/models/models_visualization.rst +0 -0
  173. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/docs/sg_execution_times.rst +0 -0
  174. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/pyproject.toml +0 -0
  175. {braindecode-1.6.1.dev1065 → braindecode-1.6.1.dev1073}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.6.1.dev1065
3
+ Version: 1.6.1.dev1073
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,7 +105,15 @@ 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 > 0:
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:
109
117
  # Uses the mask to define the output
110
118
  out_X[mask, ...], tr_y = self.operation(
111
119
  out_X[mask, ...],
@@ -168,23 +176,47 @@ class Compose(Transform):
168
176
  return X, y
169
177
 
170
178
 
171
- def _make_collateable(transform, device=None):
172
- """Wraps a transform to make it collateable.
173
-
174
- with device control.
175
- """
179
+ class _AugmentationCollate:
180
+ """Collate that applies a transform to each batch, with optional expansion.
176
181
 
177
- def _collate_fn(batch):
178
- collated_batch = default_collate(batch)
179
- X, y = collated_batch[:2]
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.
180
185
 
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
+ 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.
197
+ """
186
198
 
187
- return _collate_fn
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)
188
220
 
189
221
 
190
222
  class AugmentedDataLoader(DataLoader):
@@ -198,28 +230,44 @@ class AugmentedDataLoader(DataLoader):
198
230
  Transform or sequence of Transform to be applied to each batch.
199
231
  device : str | torch.device | None, optional
200
232
  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)``.
201
242
  **kwargs : dict, optional
202
243
  keyword arguments to pass to standard DataLoader class.
203
244
  """
204
245
 
205
- def __init__(self, dataset, transforms=None, device=None, **kwargs):
246
+ def __init__(
247
+ self, dataset, transforms=None, device=None, n_augmentation=0, **kwargs
248
+ ):
206
249
  if "collate_fn" in kwargs:
207
250
  raise ValueError(
208
251
  "collate_fn cannot be used in this context because it is used "
209
252
  "to pass transform"
210
253
  )
254
+ if n_augmentation < 0:
255
+ raise ValueError("n_augmentation must be a non-negative integer.")
211
256
  if transforms is None or (
212
257
  isinstance(transforms, list) and len(transforms) == 0
213
258
  ):
214
- self.collated_tr = _make_collateable(IdentityTransform(), device=device)
259
+ transform = IdentityTransform()
215
260
  elif isinstance(transforms, (Transform, nn.Module)):
216
- self.collated_tr = _make_collateable(transforms, device=device)
261
+ transform = transforms
217
262
  elif isinstance(transforms, list):
218
- self.collated_tr = _make_collateable(Compose(transforms), device=device)
263
+ transform = Compose(transforms)
219
264
  else:
220
265
  raise TypeError(
221
266
  "transforms can be either a Transform object "
222
267
  "or a list of Transform objects."
223
268
  )
224
269
 
270
+ self.collated_tr = _AugmentationCollate(
271
+ transform, device=device, n_augmentation=n_augmentation
272
+ )
225
273
  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 one_hot, pad
21
+ from torch.nn.functional import pad
22
22
 
23
23
 
24
24
  def identity(X: torch.Tensor, y: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
@@ -253,25 +253,34 @@ def channels_dropout(
253
253
  return X * mask.unsqueeze(-1), y
254
254
 
255
255
 
256
- def _make_permutation_matrix(
256
+ def _make_channel_permutation(
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
+ """
259
271
  rng = check_random_state(random_state)
260
272
  batch_size, n_channels, _ = X.shape
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
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,
270
282
  )
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
283
+ return perm
275
284
 
276
285
 
277
286
  def channels_shuffle(
@@ -314,8 +323,11 @@ def channels_shuffle(
314
323
  if p_shuffle == 0:
315
324
  return X, y
316
325
  mask = _pick_channels_randomly(X, 1 - p_shuffle, random_state)
317
- batch_permutations = _make_permutation_matrix(X, mask, random_state)
318
- return torch.matmul(batch_permutations, X), y
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
319
331
 
320
332
 
321
333
  def gaussian_noise(
@@ -1188,19 +1200,21 @@ def mask_encoding(
1188
1200
  32 (2024): 875-886.
1189
1201
  """
1190
1202
 
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
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
1204
1218
 
1205
1219
 
1206
1220
  def channels_rereference(
@@ -327,6 +327,7 @@ class HubDatasetMixin:
327
327
 
328
328
  n_recordings = len(self.datasets)
329
329
  first_ds = self.datasets[0]
330
+ descriptions = [ds.description for ds in self.datasets]
330
331
 
331
332
  # Get dataset-specific info based on type using registry
332
333
  dataset_type = get_dataset_type(first_ds)
@@ -358,6 +359,9 @@ class HubDatasetMixin:
358
359
  raise TypeError(f"Unsupported dataset type: {dataset_type}")
359
360
 
360
361
  # Create README content and save
362
+ license_value, license_needs_update = _infer_license_from_descriptions(
363
+ descriptions
364
+ )
361
365
  readme_content = _generate_readme_content(
362
366
  format_info=format_info,
363
367
  n_recordings=n_recordings,
@@ -366,6 +370,8 @@ class HubDatasetMixin:
366
370
  data_type=data_type,
367
371
  n_windows=n_windows,
368
372
  total_duration=total_duration,
373
+ license=license_value,
374
+ license_needs_update=license_needs_update,
369
375
  )
370
376
 
371
377
  # Save README
@@ -967,6 +973,8 @@ def _generate_readme_content(
967
973
  n_windows: int,
968
974
  total_duration: float | None = None,
969
975
  format: str = "zarr",
976
+ license: str = "please-specify",
977
+ license_needs_update: bool = True,
970
978
  ):
971
979
  """Generate README.md content for a dataset uploaded to the Hub.
972
980
 
@@ -988,6 +996,10 @@ def _generate_readme_content(
988
996
  Total duration in seconds across all recordings.
989
997
  format : str
990
998
  Storage format (default: "zarr").
999
+ license : str
1000
+ Dataset license string to write in YAML front matter.
1001
+ license_needs_update : bool
1002
+ Whether to append a reminder comment next to the license field.
991
1003
 
992
1004
  Returns
993
1005
  -------
@@ -1003,6 +1015,10 @@ def _generate_readme_content(
1003
1015
  str(timedelta(seconds=int(total_duration))) if total_duration else "N/A"
1004
1016
  )
1005
1017
 
1018
+ license_line = f"license: {license}"
1019
+ if license_needs_update:
1020
+ license_line += " # Please update this field to reflect your dataset's license"
1021
+
1006
1022
  return f"""---
1007
1023
  tags:
1008
1024
  - braindecode
@@ -1010,7 +1026,7 @@ tags:
1010
1026
  - neuroscience
1011
1027
  - brain-computer-interface
1012
1028
  - deep-learning
1013
- license: unknown
1029
+ {license_line}
1014
1030
  ---
1015
1031
 
1016
1032
  # EEG Dataset
@@ -1106,3 +1122,27 @@ if hasattr(dataset.datasets[0], "bids_channels"):
1106
1122
 
1107
1123
  *Created with [braindecode](https://braindecode.org)*
1108
1124
  """
1125
+
1126
+
1127
+ def _infer_license_from_descriptions(
1128
+ descriptions: list[pd.Series | None],
1129
+ ) -> tuple[str, bool]:
1130
+ """Infer a single dataset license from descriptions.
1131
+
1132
+ Returns inferred license and whether a manual update reminder is needed.
1133
+ """
1134
+ licenses = set()
1135
+ for description in descriptions:
1136
+ if description is None:
1137
+ continue
1138
+ raw_license = description.get("license", None)
1139
+ if raw_license is None:
1140
+ continue
1141
+ normalized = str(raw_license).strip()
1142
+ if normalized and normalized.lower() != "nan":
1143
+ licenses.add(normalized)
1144
+
1145
+ if len(licenses) == 1:
1146
+ return next(iter(licenses)), False
1147
+
1148
+ return "please-specify", True
@@ -54,6 +54,7 @@ from .sleep_stager_blanco_2020 import SleepStagerBlanco2020
54
54
  from .sleep_stager_chambon_2018 import SleepStagerChambon2018
55
55
  from .sparcnet import SPARCNet
56
56
  from .sstdpn import SSTDPN
57
+ from .steegformer import STEEGFormer
57
58
  from .syncnet import SyncNet
58
59
  from .tcformer import TCFormer
59
60
  from .tcn import BDTCN, TCN
@@ -129,6 +130,7 @@ __all__ = [
129
130
  "SleepStagerBlanco2020",
130
131
  "SleepStagerChambon2018",
131
132
  "SPARCNet",
133
+ "STEEGFormer",
132
134
  "SyncNet",
133
135
  "BDTCN",
134
136
  "TCFormer",
@@ -4,9 +4,16 @@
4
4
  # License: BSD-3
5
5
  from einops.layers.torch import Rearrange
6
6
  from torch import nn
7
+ from torch.nn.utils.parametrize import register_parametrization
7
8
 
8
9
  from braindecode.models.base import EEGModuleMixin
9
- from braindecode.modules import DepthwiseConv2d, Ensure4d, InceptionBlock
10
+ from braindecode.modules import (
11
+ DepthwiseConv2d,
12
+ Ensure4d,
13
+ InceptionBlock,
14
+ LinearWithConstraint,
15
+ MaxNormParametrize,
16
+ )
10
17
 
11
18
 
12
19
  class EEGITNet(EEGModuleMixin, nn.Sequential):
@@ -95,7 +102,9 @@ class EEGITNet(EEGModuleMixin, nn.Sequential):
95
102
  sfreq=sfreq,
96
103
  )
97
104
  self.mapping = {
98
- "classification.1.weight": "final_layer.weight",
105
+ # final_layer is max-norm constrained, so its weight lives under the
106
+ # parametrization buffer rather than ``final_layer.weight``.
107
+ "classification.1.weight": "final_layer.parametrizations.weight.original",
99
108
  "classification.1.bias": "final_layer.bias",
100
109
  }
101
110
 
@@ -185,8 +194,10 @@ class EEGITNet(EEGModuleMixin, nn.Sequential):
185
194
  self.add_module(
186
195
  "dim_reduction",
187
196
  nn.Sequential(
188
- nn.Conv2d(tcn_in_channel, tcn_in_channel * 2, kernel_size=(1, 1)),
189
- nn.BatchNorm2d(tcn_in_channel * 2),
197
+ # The authors' DR layer keeps the width (14 filters, paper III-C),
198
+ # it does not double it.
199
+ nn.Conv2d(tcn_in_channel, tcn_in_channel, kernel_size=(1, 1)),
200
+ nn.BatchNorm2d(tcn_in_channel),
190
201
  activation(),
191
202
  nn.AvgPool2d((1, tcn_kernel_size)),
192
203
  nn.Dropout(drop_prob),
@@ -198,7 +209,11 @@ class EEGITNet(EEGModuleMixin, nn.Sequential):
198
209
 
199
210
  num_features = self.get_output_shape()[-1]
200
211
 
201
- self.add_module("final_layer", nn.Linear(num_features, self.n_outputs))
212
+ # The authors constrain the final dense with ``max_norm(0.25)``.
213
+ self.add_module(
214
+ "final_layer",
215
+ LinearWithConstraint(num_features, self.n_outputs, max_norm=0.25),
216
+ )
202
217
 
203
218
  @staticmethod
204
219
  def _get_inception_branch(
@@ -208,6 +223,18 @@ class EEGITNet(EEGModuleMixin, nn.Sequential):
208
223
  depth_multiplier=1,
209
224
  activation: type[nn.Module] = nn.ELU,
210
225
  ):
226
+ # The authors constrain the spatial depthwise conv with
227
+ # ``depthwise_constraint = MaxNorm(max_value=1)``.
228
+ spatial_depthwise = DepthwiseConv2d(
229
+ out_channels,
230
+ kernel_size=(in_channels, 1),
231
+ depth_multiplier=depth_multiplier,
232
+ bias=False,
233
+ padding="valid",
234
+ )
235
+ register_parametrization(
236
+ spatial_depthwise, "weight", MaxNormParametrize(max_norm=1.0)
237
+ )
211
238
  return nn.Sequential(
212
239
  nn.Conv2d(
213
240
  1,
@@ -217,13 +244,7 @@ class EEGITNet(EEGModuleMixin, nn.Sequential):
217
244
  bias=False,
218
245
  ),
219
246
  nn.BatchNorm2d(out_channels),
220
- DepthwiseConv2d(
221
- out_channels,
222
- kernel_size=(in_channels, 1),
223
- depth_multiplier=depth_multiplier,
224
- bias=False,
225
- padding="valid",
226
- ),
247
+ spatial_depthwise,
227
248
  nn.BatchNorm2d(out_channels),
228
249
  activation(),
229
250
  )
@@ -504,6 +504,11 @@ class _InceptionBlock(nn.Module):
504
504
  out_channels=filters_per_branch * len(scales_samples),
505
505
  kernel_size=(1, 1, ncha),
506
506
  padding=(0, 0, 0),
507
+ # depthwise/grouped spatial conv with no bias, as in
508
+ # the authors' ``unit_dconv`` (per-filter spatial
509
+ # filtering, not dense mixing across filters).
510
+ groups=filters_per_branch * len(scales_samples),
511
+ bias=False,
507
512
  ),
508
513
  nn.BatchNorm3d(filters_per_branch * len(scales_samples)),
509
514
  activation,
@@ -621,6 +626,10 @@ class _ResidualBlock(nn.Module):
621
626
  out_channels=filters,
622
627
  kernel_size=(1, 1, ncha), # Spatial convolution
623
628
  padding=(0, 0, 0),
629
+ # depthwise/grouped spatial conv with no bias, as in
630
+ # the authors' ``unit_dconv``.
631
+ groups=filters,
632
+ bias=False,
624
633
  ),
625
634
  nn.BatchNorm3d(filters),
626
635
  activation,
@@ -186,9 +186,13 @@ class MSVTNet(EEGModuleMixin, nn.Module):
186
186
 
187
187
  x = self.final_layer(x)
188
188
  if self.return_features:
189
- # x shape after final layer: [batch_size, num_classes]
190
- # branch_preds shape: [batch_size, num_classes]
191
- return torch.stack(branch_preds)
189
+ # Return BOTH the main-head logits and the stacked branch logits, as
190
+ # in the authors' implementation (``return x, bx``). This is required
191
+ # for the paper's joint deep-supervision loss
192
+ # ``lambda * CE(main) + (1 - lambda) * sum_i CE(branch_i)`` and lets
193
+ # callers score on the main head.
194
+ # x: [batch_size, n_classes]; branches: [n_branches, batch_size, n_classes]
195
+ return x, torch.stack(branch_preds)
192
196
  return x
193
197
 
194
198