braindecode 1.8.1.dev169692045__tar.gz → 1.8.1.dev169698056__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.dev169692045 → braindecode-1.8.1.dev169698056}/NOTICE.txt +0 -1
  2. {braindecode-1.8.1.dev169692045/braindecode.egg-info → braindecode-1.8.1.dev169698056}/PKG-INFO +2 -2
  3. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/augmentation/functional.py +4 -2
  4. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/chb_mit.py +5 -39
  5. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/siena.py +5 -39
  6. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/sleep_physio_challe_18.py +0 -46
  7. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/utils.py +37 -0
  8. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/functional/initialization.py +14 -9
  9. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/brainbert.py +47 -16
  10. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/mapa.py +20 -12
  11. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/medformer.py +0 -18
  12. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/neurorvq.py +3 -17
  13. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/neurorvq_tokenizer.py +28 -6
  14. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/popt.py +175 -4
  15. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/sinc_shallow.py +15 -0
  16. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/tmsanet.py +11 -0
  17. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/util.py +23 -149
  18. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/zuna.py +77 -26
  19. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/blocks.py +16 -4
  20. braindecode-1.8.1.dev169698056/braindecode/version.py +1 -0
  21. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056/braindecode.egg-info}/PKG-INFO +2 -2
  22. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode.egg-info/SOURCES.txt +0 -2
  23. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode.egg-info/requires.txt +1 -1
  24. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/whats_new.rst +20 -0
  25. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/pyproject.toml +2 -2
  26. braindecode-1.8.1.dev169692045/braindecode/datasets/bids/format.py +0 -717
  27. braindecode-1.8.1.dev169692045/braindecode/modules/popt_modules.py +0 -187
  28. braindecode-1.8.1.dev169692045/braindecode/version.py +0 -1
  29. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/LICENSE.txt +0 -0
  30. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/MANIFEST.in +0 -0
  31. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/README.rst +0 -0
  32. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/__init__.py +0 -0
  33. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/augmentation/__init__.py +0 -0
  34. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/augmentation/base.py +0 -0
  35. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/augmentation/transforms.py +0 -0
  36. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/classifier.py +0 -0
  37. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/__init__.py +0 -0
  38. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/_notebook_viewer.py +0 -0
  39. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/base.py +0 -0
  40. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/bbci.py +0 -0
  41. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/bcicomp.py +0 -0
  42. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/bids/__init__.py +0 -0
  43. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/bids/datasets.py +0 -0
  44. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/bids/hub.py +0 -0
  45. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/bids/hub_format.py +0 -0
  46. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/bids/hub_io.py +0 -0
  47. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/bids/hub_validation.py +0 -0
  48. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/bids/iterable.py +0 -0
  49. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/collate.py +0 -0
  50. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/mne.py +0 -0
  51. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/moabb.py +0 -0
  52. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/nmt.py +0 -0
  53. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/registry.py +0 -0
  54. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/sleep_physionet.py +0 -0
  55. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/tuh.py +0 -0
  56. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datasets/xy.py +0 -0
  57. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datautil/__init__.py +0 -0
  58. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datautil/channel_utils.py +0 -0
  59. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datautil/hub_formats.py +0 -0
  60. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datautil/serialization.py +0 -0
  61. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/datautil/util.py +0 -0
  62. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/eegneuralnet.py +0 -0
  63. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/functional/__init__.py +0 -0
  64. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/functional/_real_dft.py +0 -0
  65. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/functional/functions.py +0 -0
  66. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/__init__.py +0 -0
  67. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/atcnet.py +0 -0
  68. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/attentionbasenet.py +0 -0
  69. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/attn_sleep.py +0 -0
  70. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/axon.py +0 -0
  71. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/barista.py +0 -0
  72. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/base.py +0 -0
  73. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/bendr.py +0 -0
  74. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/biot.py +0 -0
  75. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/brainmodule.py +0 -0
  76. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/brainomni.py +0 -0
  77. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/brant.py +0 -0
  78. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/cbramod.py +0 -0
  79. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/codebrain.py +0 -0
  80. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/config.py +0 -0
  81. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/contrawr.py +0 -0
  82. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/csbrain.py +0 -0
  83. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/ctnet.py +0 -0
  84. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/dance.py +0 -0
  85. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/deep4.py +0 -0
  86. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/deepsleepnet.py +0 -0
  87. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/dgcnn.py +0 -0
  88. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/diver1.py +0 -0
  89. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/duin.py +0 -0
  90. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/eeg_clip.py +0 -0
  91. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/eegconformer.py +0 -0
  92. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/eegdino.py +0 -0
  93. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/eeginception_erp.py +0 -0
  94. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/eeginception_mi.py +0 -0
  95. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/eegitnet.py +0 -0
  96. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/eegminer.py +0 -0
  97. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/eegnet.py +0 -0
  98. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/eegnex.py +0 -0
  99. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/eegpt.py +0 -0
  100. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/eegsimpleconv.py +0 -0
  101. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/eegsym.py +0 -0
  102. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/eegtcnet.py +0 -0
  103. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/emg2qwerty.py +0 -0
  104. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/epint.py +0 -0
  105. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/fbcnet.py +0 -0
  106. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/fblightconvnet.py +0 -0
  107. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/fbmsnet.py +0 -0
  108. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/gcnsnet.py +0 -0
  109. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/guetschel2026.py +0 -0
  110. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/hybrid.py +0 -0
  111. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/ifnet.py +0 -0
  112. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/labram.py +0 -0
  113. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/luna.py +0 -0
  114. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/meta_neuromotor.py +0 -0
  115. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/mirepnet.py +0 -0
  116. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/mscformer.py +0 -0
  117. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/msvtnet.py +0 -0
  118. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/mvpformer.py +0 -0
  119. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/neuropose.py +0 -0
  120. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/patchedtransformer.py +0 -0
  121. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/reve.py +0 -0
  122. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/sccnet.py +0 -0
  123. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/seizure_transformer.py +0 -0
  124. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/sensingdynamics.py +0 -0
  125. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/shallow_fbcsp.py +0 -0
  126. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/signal_jepa.py +0 -0
  127. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
  128. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  129. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/sleepfm.py +0 -0
  130. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/sparcnet.py +0 -0
  131. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/sstdpn.py +0 -0
  132. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/steegformer.py +0 -0
  133. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/summary.csv +0 -0
  134. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/syncnet.py +0 -0
  135. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/tcformer.py +0 -0
  136. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/tcn.py +0 -0
  137. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/tfm_tokenizer.py +0 -0
  138. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/tidnet.py +0 -0
  139. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/tsinception.py +0 -0
  140. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/usleep.py +0 -0
  141. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/models/vemg2pose.py +0 -0
  142. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/__init__.py +0 -0
  143. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/activation.py +0 -0
  144. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/attention.py +0 -0
  145. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/channels.py +0 -0
  146. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/convolution.py +0 -0
  147. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/dance_modules.py +0 -0
  148. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/filter.py +0 -0
  149. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/layers.py +0 -0
  150. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/linear.py +0 -0
  151. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/linear_attention.py +0 -0
  152. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/parametrization.py +0 -0
  153. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/quantization.py +0 -0
  154. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/stats.py +0 -0
  155. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/util.py +0 -0
  156. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/modules/wrapper.py +0 -0
  157. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/preprocessing/__init__.py +0 -0
  158. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
  159. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/preprocessing/mne_preprocess.py +0 -0
  160. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/preprocessing/preprocess.py +0 -0
  161. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/preprocessing/util.py +0 -0
  162. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/preprocessing/windowers.py +0 -0
  163. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/regressor.py +0 -0
  164. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/samplers/__init__.py +0 -0
  165. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/samplers/base.py +0 -0
  166. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/samplers/ssl.py +0 -0
  167. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/training/__init__.py +0 -0
  168. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/training/callbacks.py +0 -0
  169. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/training/losses.py +0 -0
  170. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/training/scoring.py +0 -0
  171. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/util.py +0 -0
  172. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/visualization/__init__.py +0 -0
  173. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/visualization/activations.py +0 -0
  174. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/visualization/attribution.py +0 -0
  175. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/visualization/confusion_matrices.py +0 -0
  176. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/visualization/frequency.py +0 -0
  177. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/visualization/metrics.py +0 -0
  178. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/visualization/sanity.py +0 -0
  179. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode/visualization/topology.py +0 -0
  180. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode.egg-info/dependency_links.txt +0 -0
  181. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/braindecode.egg-info/top_level.txt +0 -0
  182. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/Makefile +0 -0
  183. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/_templates/autosummary/class.rst +0 -0
  184. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  185. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/_templates/autosummary/function.rst +0 -0
  186. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  187. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/agent_docs.rst +0 -0
  188. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/api.rst +0 -0
  189. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/cite.rst +0 -0
  190. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/conf.py +0 -0
  191. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/help.rst +0 -0
  192. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/index.rst +0 -0
  193. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/install/install.rst +0 -0
  194. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/install/install_pip.rst +0 -0
  195. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/install/install_source.rst +0 -0
  196. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/models/categorization/attention.rst +0 -0
  197. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/models/categorization/channel.rst +0 -0
  198. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/models/categorization/convolution.rst +0 -0
  199. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/models/categorization/filterbank.rst +0 -0
  200. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/models/categorization/gnn.rst +0 -0
  201. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/models/categorization/interpretable.rst +0 -0
  202. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/models/categorization/lbm.rst +0 -0
  203. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/models/categorization/recurrent.rst +0 -0
  204. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/models/categorization/spd.rst +0 -0
  205. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/models/models.rst +0 -0
  206. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/models/models_categorization.rst +0 -0
  207. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/models/models_table.rst +0 -0
  208. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/models/models_visualization.rst +0 -0
  209. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/sg_execution_times.rst +0 -0
  210. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/docs/user_guide/channel_strategies.rst +0 -0
  211. {braindecode-1.8.1.dev169692045 → braindecode-1.8.1.dev169698056}/setup.cfg +0 -0
@@ -47,7 +47,6 @@ The following components are licensed under the MIT License:
47
47
  - `braindecode/models/mirepnet.py`
48
48
  - `braindecode/models/popt.py`
49
49
  - `braindecode/models/tfm_tokenizer.py`
50
- - `braindecode/modules/popt_modules.py`
51
50
  - `braindecode/models/brainomni.py`
52
51
  - `braindecode/modules/quantization.py`
53
52
  - `braindecode/modules/linear_attention.py`
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.8.1.dev169692045
3
+ Version: 1.8.1.dev169698056
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>
@@ -32,8 +32,8 @@ Requires-Dist: joblib
32
32
  Requires-Dist: torchinfo
33
33
  Requires-Dist: pandas
34
34
  Requires-Dist: wfdb>=4.3.1
35
- Requires-Dist: linear_attention_transformer
36
35
  Requires-Dist: docstring_inheritance
36
+ Requires-Dist: einops
37
37
  Requires-Dist: pydantic>=2.0
38
38
  Provides-Extra: moabb
39
39
  Requires-Dist: moabb>=1.4.3; extra == "moabb"
@@ -1089,10 +1089,12 @@ def mixup(
1089
1089
  Online: https://arxiv.org/abs/1710.09412
1090
1090
  .. [2] https://github.com/facebookresearch/mixup-cifar10/blob/master/train.py
1091
1091
  """
1092
- device = X.device
1093
1092
  batch_size, n_channels, n_times = X.shape
1094
1093
 
1095
- 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
+ )
1096
1098
  y_a = y.clone()
1097
1099
  y_b = y[idx_perm].clone()
1098
1100
 
@@ -16,12 +16,7 @@ It reorganizes the file structure to comply with the BIDS specification. To this
16
16
  # License: BSD (3-clause)
17
17
  from __future__ import annotations
18
18
 
19
- from pathlib import Path
20
-
21
- from mne.datasets import fetch_dataset
22
-
23
- from braindecode.datasets import BIDSDataset
24
- from braindecode.datasets.utils import _correct_dataset_path
19
+ from braindecode.datasets.utils import _ZenodoBIDSDataset
25
20
 
26
21
  CHB_MIT_URL = "https://zenodo.org/records/10259996/files/BIDS_CHB-MIT.zip"
27
22
  CHB_MIT_archive_name = "chb_mit_bids.zip"
@@ -38,7 +33,7 @@ CHB_MIT_dataset_params = {
38
33
  }
39
34
 
40
35
 
41
- class CHBMIT(BIDSDataset):
36
+ class CHBMIT(_ZenodoBIDSDataset):
42
37
  """The Children's Hospital Boston EEG Dataset.
43
38
 
44
39
  This database, collected at the Children's Hospital Boston, consists of EEG recordings
@@ -129,35 +124,6 @@ class CHBMIT(BIDSDataset):
129
124
  .. footbibliography::
130
125
  """
131
126
 
132
- def __init__(self, root=None, *args, **kwargs):
133
- # Download dataset if not present
134
- if root is None:
135
- path_root = fetch_dataset(
136
- dataset_params=CHB_MIT_dataset_params,
137
- path=None,
138
- processor="unzip",
139
- force_update=False,
140
- )
141
- # First time we fetch the dataset, we need to move the files to the
142
- # correct directory.
143
- path_root = _correct_dataset_path(
144
- path_root, CHB_MIT_archive_name, "BIDS_CHB-MIT"
145
- )
146
- else:
147
- # Validate that the provided root is a valid BIDS dataset
148
- if not Path(f"{root}/participants.tsv").exists():
149
- raise ValueError(
150
- f"The provided root directory {root} does not contain a valid "
151
- "BIDS dataset (missing participants.tsv). Please ensure the "
152
- "root points directly to the BIDS dataset directory."
153
- )
154
- path_root = root
155
-
156
- kwargs["root"] = path_root
157
-
158
- super().__init__(
159
- *args,
160
- extensions=".edf",
161
- check=False,
162
- **kwargs,
163
- )
127
+ _dataset_params = CHB_MIT_dataset_params
128
+ _archive_name = CHB_MIT_archive_name
129
+ _unzipped_dir = "BIDS_CHB-MIT"
@@ -15,12 +15,7 @@ It reorganizes the file structure to comply with the BIDS specification. To this
15
15
  # License: BSD (3-clause)
16
16
  from __future__ import annotations
17
17
 
18
- from pathlib import Path
19
-
20
- from mne.datasets import fetch_dataset
21
-
22
- from braindecode.datasets import BIDSDataset
23
- from braindecode.datasets.utils import _correct_dataset_path
18
+ from braindecode.datasets.utils import _ZenodoBIDSDataset
24
19
 
25
20
  SIENA_URL = "https://zenodo.org/records/10640762/files/BIDS_Siena.zip"
26
21
  SIENA_archive_name = "SIENA.zip"
@@ -37,7 +32,7 @@ SIENA_dataset_params = {
37
32
  }
38
33
 
39
34
 
40
- class SIENA(BIDSDataset):
35
+ class SIENA(_ZenodoBIDSDataset):
41
36
  """The Siena EEG Dataset.
42
37
 
43
38
  The database consists of EEG recordings of 14 patients acquired at the Unit of Neurology
@@ -128,35 +123,6 @@ class SIENA(BIDSDataset):
128
123
  automated seizure detection algorithms. Epilepsia, 66, 14-24.
129
124
  """
130
125
 
131
- def __init__(self, root=None, *args, **kwargs):
132
- # Download dataset if not present
133
- if root is None:
134
- path_root = fetch_dataset(
135
- dataset_params=SIENA_dataset_params,
136
- path=None,
137
- processor="unzip",
138
- force_update=False,
139
- )
140
- # First time we fetch the dataset, we need to move the files to the
141
- # correct directory.
142
- path_root = _correct_dataset_path(
143
- path_root, SIENA_archive_name, "BIDS_Siena"
144
- )
145
- else:
146
- # Validate that the provided root is a valid BIDS dataset
147
- if not Path(f"{root}/participants.tsv").exists():
148
- raise ValueError(
149
- f"The provided root directory {root} does not contain a valid "
150
- "BIDS dataset (missing participants.tsv). Please ensure the "
151
- "root points directly to the BIDS dataset directory."
152
- )
153
- path_root = root
154
-
155
- kwargs["root"] = path_root
156
-
157
- super().__init__(
158
- *args,
159
- extensions=".edf",
160
- check=False,
161
- **kwargs,
162
- )
126
+ _dataset_params = SIENA_dataset_params
127
+ _archive_name = SIENA_archive_name
128
+ _unzipped_dir = "BIDS_Siena"
@@ -57,52 +57,6 @@ def ensure_metafiles_exist():
57
57
  _download_if_missing(file_path, url)
58
58
 
59
59
 
60
- def _update_pc18_sleep_records(fname=PC18_RECORDS):
61
- """Create CSV file with information about available PC18 recordings."""
62
- # Load and massage the checksums.
63
- sha_train_df = pd.read_csv(
64
- PC18_SHA1_TRAINING,
65
- sep=" ",
66
- header=None,
67
- names=["sha", "fname"],
68
- engine="python",
69
- )
70
- sha_test_df = pd.read_csv(
71
- PC18_SHA1_TEST, sep=" ", header=None, names=["sha", "fname"], engine="python"
72
- )
73
- sha_train_df["Split"] = "training"
74
- sha_test_df["Split"] = "test"
75
- sha_df = pd.concat([sha_train_df, sha_test_df], axis=0, ignore_index=True)
76
- select_records = (
77
- sha_df.fname.str.startswith("tr") | sha_df.fname.str.startswith("te")
78
- ) & ~sha_df.fname.str.endswith("arousal.mat")
79
- sha_df = sha_df[select_records]
80
- sha_df["Record"] = sha_df["fname"].str.split("/", expand=True)[0]
81
- sha_df["fname"] = sha_df[["Split", "fname"]].agg("/".join, axis=1)
82
-
83
- # Load and massage the data.
84
- data = pd.read_csv(PC18_INFO)
85
-
86
- data = data.reset_index().rename({"index": "Subject"}, axis=1)
87
- data["Sex"] = (
88
- data["Sex"].map({"F": "female", "M": "male", "m": "male"}).astype("category")
89
- )
90
- data = sha_df.merge(data, on="Record")
91
-
92
- data["Record type"] = (
93
- data["fname"]
94
- .str.split(".", expand=True)[1]
95
- .map({"hea": "Header", "mat": "PSG", "arousal": "Arousal"})
96
- .astype("category")
97
- )
98
- data = data[
99
- ["Subject", "Record", "Record type", "Split", "Age", "Sex", "sha", "fname"]
100
- ].sort_values(by="Subject")
101
-
102
- # Save the data.
103
- data.to_csv(fname, index=False)
104
-
105
-
106
60
  def _data_path(path=None):
107
61
  """Get path to local copy of PC18 dataset."""
108
62
  key = "PC18_DATASET_PATH"
@@ -9,6 +9,10 @@ from __future__ import annotations
9
9
  import os
10
10
  from pathlib import Path
11
11
 
12
+ from mne.datasets import fetch_dataset
13
+
14
+ from .bids import BIDSDataset
15
+
12
16
 
13
17
  def _correct_dataset_path(
14
18
  path: str, archive_name: str, subfolder_name: str | None = None
@@ -65,3 +69,36 @@ def _correct_dataset_path(
65
69
  path = subfolder_path
66
70
 
67
71
  return path
72
+
73
+
74
+ class _ZenodoBIDSDataset(BIDSDataset):
75
+ """A BIDS dataset in EDF files, downloaded from a Zenodo archive when no
76
+ ``root`` is given. Subclasses set the three class attributes below."""
77
+
78
+ _dataset_params: dict
79
+ _archive_name: str # the downloaded archive
80
+ _unzipped_dir: str # the folder the archive extracts to
81
+
82
+ def __init__(self, root=None, *args, **kwargs):
83
+ if root is None:
84
+ path_root = fetch_dataset(
85
+ dataset_params=self._dataset_params,
86
+ path=None,
87
+ processor="unzip",
88
+ force_update=False,
89
+ )
90
+ # The first fetch extracts into a nested folder: point at the data.
91
+ path_root = _correct_dataset_path(
92
+ path_root, self._archive_name, self._unzipped_dir
93
+ )
94
+ elif not Path(f"{root}/participants.tsv").exists():
95
+ raise ValueError(
96
+ f"The provided root directory {root} does not contain a valid "
97
+ "BIDS dataset (missing participants.tsv). Please ensure the "
98
+ "root points directly to the BIDS dataset directory."
99
+ )
100
+ else:
101
+ path_root = root
102
+ super().__init__(
103
+ *args, root=path_root, extensions=".edf", check=False, **kwargs
104
+ )
@@ -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):
@@ -8,6 +8,8 @@ the STFT front-end moved inside the model. See :class:`BrainBERT`.
8
8
 
9
9
  from __future__ import annotations
10
10
 
11
+ import warnings
12
+
11
13
  import torch
12
14
  import torch.nn as nn
13
15
  import torch.nn.functional as F
@@ -16,6 +18,11 @@ from einops.layers.torch import Rearrange, Reduce
16
18
  from braindecode.functional import sinusoidal_positional_encoding, spectral_input
17
19
  from braindecode.models.base import EEGModuleMixin
18
20
  from braindecode.models.util import warn_if_sfreq_differs
21
+ from braindecode.modules.blocks import (
22
+ _check_on_non_divisible,
23
+ _pad_or_crop_to_patches,
24
+ _patch_count,
25
+ )
19
26
 
20
27
 
21
28
  class BrainBERT(EEGModuleMixin, nn.Module, license="unknown"):
@@ -122,6 +129,14 @@ class BrainBERT(EEGModuleMixin, nn.Module, license="unknown"):
122
129
  pretrained).
123
130
  drop_prob : float, optional
124
131
  Dropout probability. Default 0.1.
132
+ on_non_divisible : {"pad", "crop", "error"}, optional
133
+ A window too short to give the ``pool_n_frames`` frames the pooling
134
+ needs (``n_times < 1401`` with the defaults). ``"pad"`` (default)
135
+ adds the missing STFT frames as zeros, half before and half after the
136
+ window, with a warning at construction: the ``stft_clip`` frames at
137
+ each end are trimmed and the centre ones pooled, so the signal stays
138
+ in the pooled frames. ``"crop"`` and ``"error"`` raise. A long enough
139
+ window gives the same output under all three.
125
140
 
126
141
  References
127
142
  ----------
@@ -147,6 +162,7 @@ class BrainBERT(EEGModuleMixin, nn.Module, license="unknown"):
147
162
  pool_n_frames: int | None = 10,
148
163
  activation: type[nn.Module] = nn.GELU,
149
164
  drop_prob: float = 0.1,
165
+ on_non_divisible: str = "pad",
150
166
  # --- braindecode mandatory signal parameters ---
151
167
  n_outputs=None,
152
168
  n_chans=None,
@@ -176,6 +192,7 @@ class BrainBERT(EEGModuleMixin, nn.Module, license="unknown"):
176
192
  f"pool_n_frames must be positive; got {pool_n_frames}. "
177
193
  "Pass None to average every frame instead."
178
194
  )
195
+ _check_on_non_divisible(on_non_divisible)
179
196
  self.pool_n_frames = pool_n_frames
180
197
  self.min_frames = 1 if pool_n_frames is None else pool_n_frames
181
198
  warn_if_sfreq_differs("BrainBERT", self._sfreq, 2048)
@@ -186,15 +203,22 @@ class BrainBERT(EEGModuleMixin, nn.Module, license="unknown"):
186
203
  idx_freq_cutoff=idx_freq_cutoff,
187
204
  clip=stft_clip,
188
205
  zscore_before_clip=stft_zscore_before_clip,
206
+ min_frames=self.min_frames if on_non_divisible == "pad" else 0,
189
207
  )
190
208
  n_frames = self.spectrogram.n_frames(self.n_times)
191
209
  if n_frames < self.min_frames:
192
210
  min_n_times = self.spectrogram.min_n_times(self.min_frames)
193
- raise ValueError(
211
+ message = (
194
212
  f"n_times={self.n_times} gives {n_frames} STFT frames; the pooling "
195
- f"needs {self.min_frames}, i.e. n_times >= {min_n_times} with these "
196
- "STFT settings."
213
+ f"needs {self.min_frames}, i.e. n_times >= {min_n_times} with "
214
+ "these STFT settings"
197
215
  )
216
+ if on_non_divisible != "pad":
217
+ raise ValueError(message + ".")
218
+ warnings.warn(
219
+ message + ": the input will be padded.", UserWarning, stacklevel=2
220
+ )
221
+ n_frames = self.min_frames
198
222
 
199
223
  # The re-hosted Hub checkpoint already uses this port's names. The
200
224
  # authors' original ``.pth`` calls the input block ``input_encoding``;
@@ -329,6 +353,10 @@ class _STFTSpectrogram(nn.Module):
329
353
  Number of boundary frames trimmed from each end.
330
354
  zscore_before_clip : bool
331
355
  Whether the per-bin z-score over time precedes the trimming.
356
+ min_frames : int
357
+ A signal giving fewer output frames gets the missing STFT frames as
358
+ zeros, half before and half after it. ``0`` (default): scipy's framing
359
+ only.
332
360
  """
333
361
 
334
362
  def __init__(
@@ -338,6 +366,7 @@ class _STFTSpectrogram(nn.Module):
338
366
  idx_freq_cutoff: int = 40,
339
367
  clip: int = 10,
340
368
  zscore_before_clip: bool = True,
369
+ min_frames: int = 0,
341
370
  ):
342
371
  super().__init__()
343
372
  if not 0 <= noverlap < nperseg:
@@ -355,6 +384,7 @@ class _STFTSpectrogram(nn.Module):
355
384
  self.idx_freq_cutoff = idx_freq_cutoff
356
385
  self.clip = clip
357
386
  self.zscore_before_clip = zscore_before_clip
387
+ self.min_frames = min_frames
358
388
  # "zscore" as upstream; pipelines that apply their own statistics (the
359
389
  # Neuroprobe global z-score recipes) set it to "none" on the instance.
360
390
  self.normalizing = "zscore"
@@ -365,15 +395,11 @@ class _STFTSpectrogram(nn.Module):
365
395
  "window", torch.hann_window(nperseg, periodic=True), persistent=False
366
396
  )
367
397
 
368
- def _padded_length(self, n_times: int) -> int:
369
- """Signal length after scipy's ``boundary="zeros"`` and ``padded=True``."""
370
- length = n_times + 2 * self.boundary_pad
371
- return length + (-(length - self.nperseg)) % self.step
372
-
373
398
  def n_frames(self, n_times: int) -> int:
374
- """Number of output frames for a signal of ``n_times`` samples."""
375
- n_seg = (self._padded_length(n_times) - self.nperseg) // self.step + 1
376
- return n_seg - 2 * self.clip
399
+ """Number of frames scipy's framing gives ``n_times`` samples: segments of
400
+ ``nperseg`` every ``step`` (the last one zero-padded), minus the clip."""
401
+ length = n_times + 2 * self.boundary_pad
402
+ return _patch_count(length, self.nperseg, "pad", self.step) - 2 * self.clip
377
403
 
378
404
  def min_n_times(self, n_frames: int) -> int:
379
405
  """Shortest signal that yields at least ``n_frames`` output frames."""
@@ -382,15 +408,20 @@ class _STFTSpectrogram(nn.Module):
382
408
 
383
409
  def forward(self, x: torch.Tensor) -> torch.Tensor:
384
410
  """``(batch, n_chans, n_times)`` -> ``(batch, n_chans, n_frames, cutoff)``."""
385
- # scipy boundary="zeros": half a window of zeros on each end, then
386
- # padded=True: extend so an integer number of segments fits.
387
411
  if not x.is_floating_point():
388
412
  raise TypeError(
389
413
  f"BrainBERT expects a floating-point signal, got {x.dtype}."
390
414
  )
391
- n_times = x.shape[-1]
392
- right_pad = self._padded_length(n_times) - n_times - self.boundary_pad
393
- xp = F.pad(x, (self.boundary_pad, right_pad)) # (batch, n_chans, padded)
415
+ # scipy boundary="zeros" (half a window of zeros on each end), then
416
+ # padded=True (right zero-pad so the segments tile the signal). A signal
417
+ # short of min_frames gets the missing segments as zeros, half before
418
+ # it: the clip frames at each end are trimmed, so a right pad alone
419
+ # would leave it outside the frames that are kept.
420
+ xp = F.pad(x, (self.boundary_pad, self.boundary_pad))
421
+ min_segments = self.min_frames + 2 * self.clip if self.min_frames else 1
422
+ xp = _pad_or_crop_to_patches(
423
+ xp, self.nperseg, "pad", self.step, min_segments, center=True
424
+ )
394
425
  frames = xp.unfold(-1, self.nperseg, self.step) # (b, c, n_frames, nperseg)
395
426
  frames = spectral_input(frames)
396
427
  win = self.window.to(frames)
@@ -27,7 +27,7 @@ from torch import nn
27
27
 
28
28
  from braindecode.functional import rescale_parameter, rotate_pairs, spectral_input
29
29
  from braindecode.models.base import EEGModuleMixin
30
- from braindecode.models.util import dkt_region_slots
30
+ from braindecode.models.util import _in_model_resample, dkt_region_slots
31
31
  from braindecode.modules import FeedForwardBlock
32
32
 
33
33
  # Blocks whose output carries a deep-supervision norm, following V-JEPA 2.1.
@@ -104,9 +104,11 @@ class MAPA(EEGModuleMixin, nn.Module, license="apache-2.0"):
104
104
  batch share them. Only ``pooling="flatten"`` is tied to one montage and one
105
105
  window length.
106
106
 
107
- *Sampling rate and window length.* Resample to 2048 Hz. A window yields
108
- ``1 + n_times // 64`` frames, truncated to a multiple of 8, so it needs at
109
- least 448 samples. With ``normalization="session"`` the input is the
107
+ *Sampling rate and window length.* The model reads 2048 Hz; another
108
+ integer ``sfreq`` is resampled to 2048 Hz inside the model with
109
+ :class:`torchaudio.transforms.Resample`, with a warning. A 2048 Hz window
110
+ yields ``1 + n_times // 64`` frames, truncated to a multiple of 8, so it
111
+ needs at least 448 samples. With ``normalization="session"`` the input is the
110
112
  spectrogram itself (``sfreq=32``, ``n_times`` in frames): the 20 retained
111
113
  bins, robust z-scored per contact and bin over the whole recording.
112
114
 
@@ -252,18 +254,23 @@ class MAPA(EEGModuleMixin, nn.Module, license="apache-2.0"):
252
254
  f"{normalization!r}."
253
255
  )
254
256
  # The bands are FFT bin slices at 2048 Hz on a 32 Hz frame clock, so
255
- # another rate would shift the bands and the token rate; session inputs
256
- # are already the 32 Hz spectrogram. sfreq is advisory for the
257
- # frontend, so it is validated only when it is known, and a wrong
258
- # value is a hard error rather than a silent warning.
257
+ # another raw rate is resampled to 2048 Hz in forward; session inputs
258
+ # are already the 32 Hz spectrogram. sfreq is validated only when it
259
+ # is known.
259
260
  expected_sfreq = 32 if normalization == "session" else 2048
260
261
  sfreq_known = self._sfreq is not None or (
261
262
  self._input_window_seconds is not None and self._n_times is not None
262
263
  )
264
+ self.resample: nn.Module = nn.Identity()
265
+ n_times_model = self.n_times
263
266
  if sfreq_known and float(self.sfreq) != expected_sfreq:
264
- raise ValueError(
265
- f"MAPA with normalization={normalization!r} needs sfreq="
266
- f"{expected_sfreq} Hz, got {self.sfreq} Hz."
267
+ if normalization == "session":
268
+ raise ValueError(
269
+ f"MAPA with normalization={normalization!r} needs sfreq="
270
+ f"{expected_sfreq} Hz, got {self.sfreq} Hz."
271
+ )
272
+ self.resample, n_times_model = _in_model_resample(
273
+ "MAPA", self.sfreq, 2048, self.n_times
267
274
  )
268
275
 
269
276
  self.d_model = d_model
@@ -276,7 +283,7 @@ class MAPA(EEGModuleMixin, nn.Module, license="apache-2.0"):
276
283
  self.activation = activation
277
284
 
278
285
  self.n_frames = _frame_count(
279
- self.n_times, spectrogram=normalization == "session"
286
+ n_times_model, spectrogram=normalization == "session"
280
287
  )
281
288
  self.k_full = sum(self.n_frames // stride for *_, stride in _BANDS)
282
289
 
@@ -617,6 +624,7 @@ class MAPA(EEGModuleMixin, nn.Module, license="apache-2.0"):
617
624
  f"(batch, n_chans, n_times), but got {list(x.shape)} with "
618
625
  f"normalization='{self.normalization}'."
619
626
  )
627
+ x = self.resample(x)
620
628
  indices = self._resolve_sensor_indices(sensor_indices, x)
621
629
  n_frames = _frame_count(x.shape[-1], spectrogram=spectrogram)
622
630
  if self.pooling == "flatten" and (
@@ -525,24 +525,6 @@ class _AttentionLayer(nn.Module):
525
525
  return self.out_projection(out), attn
526
526
 
527
527
 
528
- class _TriangularCausalMask:
529
- def __init__(
530
- self, batch_size: int, seq_len: int, device: Optional[torch.device] = None
531
- ):
532
- # Normalize device to a torch.device for .to(device)
533
- if device is None:
534
- device = torch.device("cpu")
535
- mask_shape = [batch_size, 1, seq_len, seq_len]
536
- with torch.no_grad():
537
- self._mask = torch.triu(
538
- torch.ones(mask_shape, dtype=torch.bool), diagonal=1
539
- ).to(device)
540
-
541
- @property
542
- def mask(self) -> torch.Tensor:
543
- return self._mask
544
-
545
-
546
528
  class _FullAttention(nn.Module):
547
529
  def __init__(
548
530
  self,
@@ -14,11 +14,11 @@ from typing import Dict, Optional, Union
14
14
  import torch
15
15
  import torch.nn.functional as F
16
16
  from torch import Tensor, nn
17
- from torchaudio.transforms import Resample
18
17
 
19
18
  from braindecode.models.base import EEGModuleMixin
20
19
  from braindecode.models.labram import _Attention
21
20
  from braindecode.models.signal_jepa import _GroupNorm
21
+ from braindecode.models.util import _in_model_resample
22
22
  from braindecode.modules import MLP, DropPath, PatchTokenizer
23
23
  from braindecode.modules.blocks import _check_on_non_divisible, _patch_count
24
24
 
@@ -534,23 +534,9 @@ class NeuroRVQ(EEGModuleMixin, nn.Module, license="cc-by-nc-4.0"):
534
534
  self.resample: nn.Module = nn.Identity()
535
535
  self._n_times_model = self.n_times
536
536
  if in_sfreq is not None and in_sfreq != preset["sfreq"]:
537
- if in_sfreq != round(in_sfreq):
538
- raise ValueError(
539
- f"NeuroRVQ resamples integer rates only, got {in_sfreq}."
540
- )
541
- warnings.warn(
542
- f"NeuroRVQ-{modality.upper()} was trained at {preset['sfreq']} Hz; the "
543
- f"{in_sfreq:g} Hz input is resampled inside the model.",
544
- UserWarning,
545
- )
546
- self.resample = Resample(int(in_sfreq), preset["sfreq"])
547
- # Derived from the rates: kept out of the state dict, so pretrained
548
- # (200 Hz) weights load into a resampling model unchanged.
549
- self.resample.register_buffer(
550
- "kernel", self.resample.kernel, persistent=False
537
+ self.resample, self._n_times_model = _in_model_resample(
538
+ f"NeuroRVQ-{modality.upper()}", in_sfreq, preset["sfreq"], self.n_times
551
539
  )
552
- # torchaudio's output length.
553
- self._n_times_model = math.ceil(self.n_times * preset["sfreq"] / in_sfreq)
554
540
  # ceil for "pad", floor for "crop", exact for "error" (raises otherwise).
555
541
  num_patches = _patch_count(self._n_times_model, patch_size, on_non_divisible)
556
542
  if num_patches > max_patches: