Braindecode 1.8.1.dev181570120__tar.gz → 1.8.1.dev181710643__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 (208) hide show
  1. {braindecode-1.8.1.dev181570120/braindecode.egg-info → braindecode-1.8.1.dev181710643}/PKG-INFO +1 -1
  2. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/base.py +5 -115
  3. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/tuh.py +4 -8
  4. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datautil/serialization.py +6 -10
  5. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/attn_sleep.py +0 -4
  6. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/base.py +15 -34
  7. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/brainomni.py +4 -14
  8. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/codebrain.py +3 -9
  9. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/contrawr.py +1 -23
  10. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/csbrain.py +36 -74
  11. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/deep4.py +1 -10
  12. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/dgcnn.py +0 -7
  13. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/diver1.py +59 -51
  14. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/eegconformer.py +2 -5
  15. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/eegnex.py +1 -16
  16. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/labram.py +14 -23
  17. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/luna.py +1 -4
  18. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/medformer.py +1 -4
  19. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/meta_neuromotor.py +8 -35
  20. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/msvtnet.py +2 -5
  21. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/neurorvq.py +3 -17
  22. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/neurorvq_tokenizer.py +53 -57
  23. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/reve.py +1 -13
  24. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/signal_jepa.py +1 -6
  25. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/sleep_stager_blanco_2020.py +6 -13
  26. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/tcn.py +0 -5
  27. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/tidnet.py +1 -18
  28. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/usleep.py +2 -3
  29. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/zuna.py +0 -6
  30. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/filter.py +33 -79
  31. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/quantization.py +6 -10
  32. braindecode-1.8.1.dev181710643/braindecode/version.py +1 -0
  33. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643/braindecode.egg-info}/PKG-INFO +1 -1
  34. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/whats_new.rst +0 -33
  35. braindecode-1.8.1.dev181570120/braindecode/version.py +0 -1
  36. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/LICENSE.txt +0 -0
  37. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/MANIFEST.in +0 -0
  38. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/NOTICE.txt +0 -0
  39. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/README.rst +0 -0
  40. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/__init__.py +0 -0
  41. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/augmentation/__init__.py +0 -0
  42. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/augmentation/base.py +0 -0
  43. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/augmentation/functional.py +0 -0
  44. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/augmentation/transforms.py +0 -0
  45. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/classifier.py +0 -0
  46. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/__init__.py +0 -0
  47. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/_notebook_viewer.py +0 -0
  48. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bbci.py +0 -0
  49. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bcicomp.py +0 -0
  50. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/__init__.py +0 -0
  51. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/datasets.py +0 -0
  52. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/format.py +0 -0
  53. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/hub.py +0 -0
  54. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/hub_format.py +0 -0
  55. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/hub_io.py +0 -0
  56. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/hub_validation.py +0 -0
  57. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/iterable.py +0 -0
  58. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/chb_mit.py +0 -0
  59. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/collate.py +0 -0
  60. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/mne.py +0 -0
  61. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/moabb.py +0 -0
  62. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/nmt.py +0 -0
  63. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/registry.py +0 -0
  64. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/siena.py +0 -0
  65. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  66. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/sleep_physionet.py +0 -0
  67. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/utils.py +0 -0
  68. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datasets/xy.py +0 -0
  69. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datautil/__init__.py +0 -0
  70. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datautil/channel_utils.py +0 -0
  71. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datautil/hub_formats.py +0 -0
  72. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/datautil/util.py +0 -0
  73. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/eegneuralnet.py +0 -0
  74. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/functional/__init__.py +0 -0
  75. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/functional/_real_dft.py +0 -0
  76. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/functional/functions.py +0 -0
  77. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/functional/initialization.py +0 -0
  78. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/__init__.py +0 -0
  79. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/atcnet.py +0 -0
  80. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/attentionbasenet.py +0 -0
  81. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/axon.py +0 -0
  82. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/barista.py +0 -0
  83. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/bendr.py +0 -0
  84. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/biot.py +0 -0
  85. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/brainbert.py +0 -0
  86. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/brainmodule.py +0 -0
  87. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/brant.py +0 -0
  88. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/cbramod.py +0 -0
  89. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/config.py +0 -0
  90. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/ctnet.py +0 -0
  91. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/dance.py +0 -0
  92. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/deepsleepnet.py +0 -0
  93. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/eeg_clip.py +0 -0
  94. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/eegdino.py +0 -0
  95. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/eeginception_erp.py +0 -0
  96. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/eeginception_mi.py +0 -0
  97. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/eegitnet.py +0 -0
  98. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/eegminer.py +0 -0
  99. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/eegnet.py +0 -0
  100. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/eegpt.py +0 -0
  101. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/eegsimpleconv.py +0 -0
  102. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/eegsym.py +0 -0
  103. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/eegtcnet.py +0 -0
  104. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/emg2qwerty.py +0 -0
  105. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/fbcnet.py +0 -0
  106. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/fblightconvnet.py +0 -0
  107. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/fbmsnet.py +0 -0
  108. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/guetschel2026.py +0 -0
  109. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/hybrid.py +0 -0
  110. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/ifnet.py +0 -0
  111. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/mapa.py +0 -0
  112. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/mirepnet.py +0 -0
  113. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/mscformer.py +0 -0
  114. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/mvpformer.py +0 -0
  115. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/neuropose.py +0 -0
  116. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/patchedtransformer.py +0 -0
  117. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/popt.py +0 -0
  118. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/sccnet.py +0 -0
  119. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/seizure_transformer.py +0 -0
  120. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/sensingdynamics.py +0 -0
  121. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/shallow_fbcsp.py +0 -0
  122. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/sinc_shallow.py +0 -0
  123. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  124. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/sleepfm.py +0 -0
  125. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/sparcnet.py +0 -0
  126. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/sstdpn.py +0 -0
  127. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/steegformer.py +0 -0
  128. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/summary.csv +0 -0
  129. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/syncnet.py +0 -0
  130. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/tcformer.py +0 -0
  131. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/tfm_tokenizer.py +0 -0
  132. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/tmsanet.py +0 -0
  133. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/tsinception.py +0 -0
  134. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/util.py +0 -0
  135. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/models/vemg2pose.py +0 -0
  136. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/__init__.py +0 -0
  137. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/activation.py +0 -0
  138. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/attention.py +0 -0
  139. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/blocks.py +0 -0
  140. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/channels.py +0 -0
  141. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/convolution.py +0 -0
  142. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/dance_modules.py +0 -0
  143. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/layers.py +0 -0
  144. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/linear.py +0 -0
  145. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/linear_attention.py +0 -0
  146. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/parametrization.py +0 -0
  147. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/popt_modules.py +0 -0
  148. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/stats.py +0 -0
  149. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/util.py +0 -0
  150. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/modules/wrapper.py +0 -0
  151. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/preprocessing/__init__.py +0 -0
  152. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
  153. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/preprocessing/mne_preprocess.py +0 -0
  154. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/preprocessing/preprocess.py +0 -0
  155. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/preprocessing/util.py +0 -0
  156. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/preprocessing/windowers.py +0 -0
  157. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/regressor.py +0 -0
  158. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/samplers/__init__.py +0 -0
  159. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/samplers/base.py +0 -0
  160. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/samplers/ssl.py +0 -0
  161. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/training/__init__.py +0 -0
  162. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/training/callbacks.py +0 -0
  163. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/training/losses.py +0 -0
  164. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/training/scoring.py +0 -0
  165. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/util.py +0 -0
  166. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/visualization/__init__.py +0 -0
  167. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/visualization/activations.py +0 -0
  168. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/visualization/attribution.py +0 -0
  169. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/visualization/confusion_matrices.py +0 -0
  170. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/visualization/frequency.py +0 -0
  171. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/visualization/metrics.py +0 -0
  172. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/visualization/sanity.py +0 -0
  173. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode/visualization/topology.py +0 -0
  174. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode.egg-info/SOURCES.txt +0 -0
  175. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode.egg-info/dependency_links.txt +0 -0
  176. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode.egg-info/requires.txt +0 -0
  177. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/braindecode.egg-info/top_level.txt +0 -0
  178. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/Makefile +0 -0
  179. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/_templates/autosummary/class.rst +0 -0
  180. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  181. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/_templates/autosummary/function.rst +0 -0
  182. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  183. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/agent_docs.rst +0 -0
  184. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/api.rst +0 -0
  185. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/cite.rst +0 -0
  186. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/conf.py +0 -0
  187. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/help.rst +0 -0
  188. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/index.rst +0 -0
  189. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/install/install.rst +0 -0
  190. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/install/install_pip.rst +0 -0
  191. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/install/install_source.rst +0 -0
  192. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/models/categorization/attention.rst +0 -0
  193. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/models/categorization/channel.rst +0 -0
  194. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/models/categorization/convolution.rst +0 -0
  195. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/models/categorization/filterbank.rst +0 -0
  196. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/models/categorization/gnn.rst +0 -0
  197. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/models/categorization/interpretable.rst +0 -0
  198. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/models/categorization/lbm.rst +0 -0
  199. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/models/categorization/recurrent.rst +0 -0
  200. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/models/categorization/spd.rst +0 -0
  201. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/models/models.rst +0 -0
  202. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/models/models_categorization.rst +0 -0
  203. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/models/models_table.rst +0 -0
  204. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/models/models_visualization.rst +0 -0
  205. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/sg_execution_times.rst +0 -0
  206. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/docs/user_guide/channel_strategies.rst +0 -0
  207. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/pyproject.toml +0 -0
  208. {braindecode-1.8.1.dev181570120 → braindecode-1.8.1.dev181710643}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.8.1.dev181570120
3
+ Version: 1.8.1.dev181710643
4
4
  Summary: Deep learning software to decode EEG, ECG or MEG signals
5
5
  Author-email: Robin Tibor Schirrmeister <robintibor@gmail.com>, Bruno Aristimunha Pinto <b.aristimunha@gmail.com>, Alexandre Gramfort <agramfort@meta.com>
6
6
  Maintainer-email: Alexandre Gramfort <agramfort@meta.com>, Bruno Aristimunha Pinto <b.aristimunha@gmail.com>, Robin Tibor Schirrmeister <robintibor@gmail.com>
@@ -14,16 +14,13 @@ from __future__ import annotations
14
14
  import bisect
15
15
  import html as _html
16
16
  import json
17
- import mmap
18
17
  import os
19
18
  import shutil
20
19
  import warnings
21
20
  from abc import abstractmethod
22
21
  from collections import Counter
23
- from collections.abc import Callable, Hashable, Sequence
22
+ from collections.abc import Callable, Hashable
24
23
  from glob import glob
25
- from itertools import chain
26
- from operator import attrgetter
27
24
  from pathlib import Path
28
25
  from typing import Any, Generic, Iterable, no_type_check
29
26
 
@@ -31,7 +28,6 @@ import mne
31
28
  import mne.io
32
29
  import numpy as np
33
30
  import pandas as pd
34
- from mne.io.constants import FIFF
35
31
  from mne.utils import _soft_import
36
32
  from mne.utils.docs import deprecated
37
33
  from torch.utils.data import ConcatDataset, Dataset, IterableDataset
@@ -224,109 +220,6 @@ def _compute_ch_pos(info, targets_from):
224
220
  return pos
225
221
 
226
222
 
227
- _TAG_ROW = attrgetter("kind", "type", "size", "next", "pos")
228
-
229
-
230
- def _tag_rows(tags):
231
- """(kind, type, size, next, pos) of FIF tags as an int64 array (n, 5)."""
232
- flat = chain.from_iterable(map(_TAG_ROW, tags))
233
- return np.fromiter(flat, np.int64, 5 * len(tags)).reshape(-1, 5)
234
-
235
-
236
- class _FifTagTable(Sequence):
237
- """The data-buffer tags of a lazy FIF raw as one int64 array.
238
-
239
- mne's FIF reader keeps one ``Tag`` object per data buffer in
240
- ``raw._raw_extras[i]["ent"]`` (one per second of signal with mne's default
241
- buffers), each with its attribute dict and integers once unpickled. A lazy
242
- dataset of many recordings holds millions of them in RAM, and every forked
243
- DataLoader worker copies the memory pages of those it reads (reference
244
- counts). This holds the same fields in 40 bytes per buffer and returns an
245
- equal ``Tag`` on access, so mne's own reads are unchanged.
246
- """
247
-
248
- def __init__(self, tags):
249
- self.tag_class = type(tags[0])
250
- self.table = _tag_rows(tags)
251
-
252
- def __len__(self):
253
- return len(self.table)
254
-
255
- def __getitem__(self, i):
256
- if isinstance(i, slice):
257
- return [self.tag_class(*row) for row in self.table[i].tolist()]
258
- return self.tag_class(*self.table[i].tolist())
259
-
260
-
261
- _TAG_FIELDS = ("kind", "type", "size", "next", "pos", "data")
262
-
263
-
264
- def _compact_fif_tags(inst):
265
- """Swap the ``Tag`` lists of a FIF raw for `_FifTagTable` (in place).
266
-
267
- Only gap-free lists of directory tags (no ``None``, no ``data``) with mne's
268
- ``Tag`` fields are swapped; anything else is left as mne built it.
269
- """
270
- for extra in getattr(inst, "_raw_extras", ()):
271
- tags = extra.get("ent")
272
- if not isinstance(tags, list) or not tags:
273
- continue
274
- cls = type(tags[0])
275
- if tuple(getattr(cls, "__dataclass_fields__", ())) == _TAG_FIELDS and all(
276
- type(t) is cls and t.data is None for t in tags
277
- ):
278
- extra["ent"] = _FifTagTable(tags)
279
- return inst
280
-
281
-
282
- def _read_fif_window(raw, start, stop):
283
- """Samples ``start:stop`` of a lazy FIF raw, copied from the file in one go.
284
-
285
- mne reads, casts and calibrates the FIF data buffers of a range one at a
286
- time (60 Python steps for a 60-s window saved with 1-s buffers, each through
287
- a buffered file whose buffer is 4 MB on network file systems). Here one
288
- slice of the memory-mapped file holds the bytes of every buffer in the
289
- range and one multiply calibrates them, with mne's arithmetic (float64 data
290
- times ``raw._cals``), so the values equal ``raw._getitem``'s. Returns None
291
- (the caller uses mne) unless ``raw`` is a lazy, single-file, uncompressed
292
- FIF raw of float32 buffers without projector, compensation or gaps.
293
- """
294
- if (
295
- not isinstance(raw, mne.io.Raw)
296
- or raw.preload
297
- or len(raw._raw_extras) != 1
298
- or raw._projector is not None
299
- or raw._comp is not None
300
- ):
301
- return None
302
- extra = raw._raw_extras[0]
303
- fname, bounds = extra["filename"], extra["bounds"]
304
- if not isinstance(fname, Path) or fname.suffix == ".gz":
305
- return None
306
- start, stop = start + raw._first_samps[0], stop + raw._first_samps[0]
307
- first = np.searchsorted(bounds, start, side="right") - 1
308
- tags = extra["ent"]
309
- if isinstance(tags, _FifTagTable):
310
- rows = tags.table[first : np.searchsorted(bounds, stop)]
311
- else:
312
- tags = tags[first : np.searchsorted(bounds, stop)]
313
- if any(t is None for t in tags):
314
- return None
315
- rows = _tag_rows(tags)
316
- if not len(rows) or (rows[:, 1] != FIFF.FIFFT_FLOAT).any():
317
- return None
318
- size, pos = rows[:, 2].tolist(), rows[:, 4].tolist()
319
- # mmap: no copy through a 4 MB read buffer, and a cold file is read around
320
- # the window by the kernel (as mne's 4 MB reads did), not window by window
321
- with open(fname, "rb") as f, mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m:
322
- buf = m[pos[0] : pos[-1] + 16 + size[-1]]
323
- one = np.concatenate(
324
- [np.frombuffer(buf, ">f4", s // 4, p + 16 - pos[0]) for s, p in zip(size, pos)]
325
- ).reshape(-1, extra["orig_nchan"])[start - bounds[first] : stop - bounds[first]]
326
- picked = one[:, raw._read_picks[0]].T
327
- return np.multiply(picked, raw._cals[:, np.newaxis], order="C")
328
-
329
-
330
223
  def _window_info(crop_inds, sfreq):
331
224
  """Extract window size from crop indices.
332
225
 
@@ -930,11 +823,9 @@ class EEGWindowsDataset(_ZarrMixin, RecordDataset):
930
823
  if self._zarr_data is not None:
931
824
  X = self._zarr_data[:, i_start:i_stop]
932
825
  else:
933
- X = _read_fif_window(self.raw, i_start, i_stop)
934
- if X is None:
935
- X = self.raw._getitem(
936
- (slice(None), slice(i_start, i_stop)), return_times=False
937
- )
826
+ X = self.raw._getitem(
827
+ (slice(None), slice(i_start, i_stop)), return_times=False
828
+ )
938
829
  X = np.array(X, dtype="float32")
939
830
  if self.transform is not None:
940
831
  X = self.transform(X)
@@ -1781,8 +1672,7 @@ class BaseConcatDataset(ConcatDataset, HubDatasetMixin, Generic[T]):
1781
1672
  kwargs_path = os.path.join(path, ".".join([kwarg_name, "json"]))
1782
1673
  kwargs = getattr(self, kwarg_name)
1783
1674
  if kwargs is not None:
1784
- with open(kwargs_path, "w") as f:
1785
- json.dump(kwargs, f)
1675
+ json.dump(kwargs, open(kwargs_path, "w"))
1786
1676
 
1787
1677
  @property
1788
1678
  def description(self) -> pd.DataFrame:
@@ -241,11 +241,7 @@ class TUH(BaseConcatDataset):
241
241
  # file paths, use this instead as before
242
242
  if "year" in description:
243
243
  meas_date = meas_date.replace(*description[["year", "month", "day"]])
244
- # FIF (e.g. preprocess(..., save_dir=...)) stores dates from 1901-12-13 to
245
- # 2038-01-19 only: undated recordings (year 1 above) and de-identified ones
246
- # (TUAB has 1899-12-30) keep their date in the description only.
247
- in_fif_range = -(2**31) <= meas_date.timestamp() < 2**31
248
- raw.set_meas_date(meas_date if in_fif_range else None)
244
+ raw.set_meas_date(meas_date)
249
245
 
250
246
  d = {
251
247
  "age": int(age),
@@ -255,9 +251,9 @@ class TUH(BaseConcatDataset):
255
251
  # if not, get it from meas_date in raw.info and add to description
256
252
  # if meas_date is None, create fake one
257
253
  if "year" not in description:
258
- d["year"] = meas_date.year
259
- d["month"] = meas_date.month
260
- d["day"] = meas_date.day
254
+ d["year"] = raw.info["meas_date"].year
255
+ d["month"] = raw.info["meas_date"].month
256
+ d["day"] = raw.info["meas_date"].day
261
257
 
262
258
  # read info relevant for preprocessing from raw without loading it
263
259
  if add_physician_reports:
@@ -21,7 +21,6 @@ from ..datasets.base import (
21
21
  EEGWindowsDataset,
22
22
  RawDataset,
23
23
  WindowsDataset,
24
- _compact_fif_tags,
25
24
  )
26
25
 
27
26
 
@@ -80,8 +79,7 @@ def _outdated_load_concat_dataset(path, preload, ids_to_load=None, target_name=N
80
79
  for path in paths:
81
80
  if is_raw and target_name is None:
82
81
  target_file_name = path / "target_name.json"
83
- with open(target_file_name) as f:
84
- target_name = json.load(f)["target_name"]
82
+ target_name = json.load(open(target_file_name, "r"))["target_name"]
85
83
 
86
84
  all_signals, description = _load_signals_and_description(
87
85
  path=path, preload=preload, is_raw=is_raw, ids_to_load=ids_to_load
@@ -143,7 +141,7 @@ def _load_signals(fif_file, preload, is_raw):
143
141
  if all(Path(f).exists() for f in signals.filenames):
144
142
  if preload:
145
143
  signals.load_data()
146
- return _compact_fif_tags(signals)
144
+ return signals
147
145
  else: # This may happen if the file has been moved together with the pickle file.
148
146
  warnings.warn(
149
147
  f"Pickle file {pkl_file} exists, but the referenced fif "
@@ -173,8 +171,7 @@ def _load_signals(fif_file, preload, is_raw):
173
171
  if preload:
174
172
  signals._data, signals.preload = data, True
175
173
 
176
- # after the pickle above, which keeps mne's own layout on disk
177
- return _compact_fif_tags(signals)
174
+ return signals
178
175
 
179
176
 
180
177
  def load_concat_dataset(path, preload, ids_to_load=None, target_name=None, n_jobs=1):
@@ -267,8 +264,7 @@ def _load_parallel(path, i, preload, is_raw, has_stored_windows):
267
264
  target_file_path = sub_dir / "target_name.json"
268
265
  target_name = None
269
266
  if target_file_path.exists():
270
- with open(target_file_path) as f:
271
- target_name = json.load(f)["target_name"]
267
+ target_name = json.load(open(target_file_path, "r"))["target_name"]
272
268
 
273
269
  if is_raw and (not has_stored_windows):
274
270
  dataset = RawDataset(signals, description, target_name)
@@ -308,8 +304,8 @@ def _load_kwargs_json(kwargs_name, sub_dir):
308
304
  kwargs_file_name = ".".join([kwargs_name, "json"])
309
305
  kwargs_file_path = os.path.join(sub_dir, kwargs_file_name)
310
306
  if os.path.exists(kwargs_file_path):
311
- with open(kwargs_file_path) as f:
312
- return json.load(f)
307
+ kwargs = json.load(open(kwargs_file_path, "r"))
308
+ return kwargs
313
309
 
314
310
 
315
311
  def _is_outdated_saved(path):
@@ -143,10 +143,6 @@ class AttnSleep(EEGModuleMixin, nn.Module):
143
143
  sfreq=sfreq,
144
144
  )
145
145
  del n_outputs, n_chans, chs_info, n_times, input_window_seconds, sfreq
146
- if self._n_chans_for_jit not in (None, 1):
147
- raise ValueError(
148
- f"AttnSleep takes single-channel input; got n_chans={self._n_chans_for_jit}."
149
- )
150
146
 
151
147
  self.mapping = {
152
148
  "fc.weight": "final_layer.weight",
@@ -46,24 +46,6 @@ _GEOMETRY_KWARGS = (
46
46
  )
47
47
 
48
48
 
49
- def _too_short_input_error(exc: RuntimeError, input_shape) -> Optional[ValueError]:
50
- """ValueError for a layer that found the input too short, else None."""
51
- if not str(exc).endswith(
52
- (
53
- "Output size is too small",
54
- "Kernel size can't be greater than actual input size",
55
- )
56
- ):
57
- return None
58
- return ValueError(
59
- "During model prediction RuntimeError was thrown showing that at some "
60
- f"layer `{str(exc).split('.')[-1]}` (see above in the stacktrace). This "
61
- "could be caused by providing too small `n_times`/`input_window_seconds`. "
62
- "Model may require longer chunks of signal in the input than "
63
- f"{input_shape}."
64
- )
65
-
66
-
67
49
  _HF_INSTALL_HINT = (
68
50
  "requires the `huggingface_hub` package. "
69
51
  "Install with: pip install 'braindecode[hub]'"
@@ -501,18 +483,6 @@ class EEGModuleMixin(_BaseHubMixin, metaclass=_BraindecodeDocstringMeta):
501
483
  # Called by torch.jit.script before compiling the model.
502
484
  return make_parametrizations_scriptable(self)
503
485
 
504
- def __call__(self, *args, **kwargs):
505
- # An input shorter than the layers need raises ValueError, not a torch
506
- # RuntimeError from deep inside forward.
507
- try:
508
- return super().__call__(*args, **kwargs)
509
- except RuntimeError as exc:
510
- shape = tuple(args[0].shape) if args and hasattr(args[0], "shape") else None
511
- error = _too_short_input_error(exc, shape)
512
- if error is None:
513
- raise
514
- raise error from exc
515
-
516
486
  def get_output_shape(self) -> tuple[int, ...]:
517
487
  """Returns shape of neural network output for batch size equal 1.
518
488
 
@@ -536,10 +506,21 @@ class EEGModuleMixin(_BaseHubMixin, metaclass=_BraindecodeDocstringMeta):
536
506
  .shape
537
507
  )
538
508
  except RuntimeError as exc:
539
- error = _too_short_input_error(exc, self.input_shape)
540
- if error is None:
541
- raise
542
- raise error from exc
509
+ if str(exc).endswith(
510
+ (
511
+ "Output size is too small",
512
+ "Kernel size can't be greater than actual input size",
513
+ )
514
+ ):
515
+ msg = (
516
+ "During model prediction RuntimeError was thrown showing that at some "
517
+ f"layer `{str(exc).split('.')[-1]}` (see above in the stacktrace). This "
518
+ "could be caused by providing too small `n_times`/`input_window_seconds`. "
519
+ "Model may require longer chunks of signal in the input than "
520
+ f"{self.input_shape}."
521
+ )
522
+ raise ValueError(msg) from exc
523
+ raise exc
543
524
 
544
525
  def get_config(self) -> dict:
545
526
  """Return a JSON-serializable dict of all ``__init__`` parameters.
@@ -29,21 +29,15 @@ from braindecode.modules.quantization import ResidualVectorQuantizer
29
29
 
30
30
 
31
31
  class _SELU(nn.SELU):
32
- """``nn.SELU`` as ``ELU(x, alpha * scale)`` times ``scale`` where ``x > 0``:
33
- same values and gradients, and trainable on Gaudi, whose ELU backward only
34
- supports ``scale == 1``."""
32
+ """``nn.SELU`` written as ``scale * x`` / ELU: same values and gradients, and
33
+ trainable on Gaudi, whose ELU backward only supports ``scale == 1``."""
35
34
 
36
35
  def forward(self, x: torch.Tensor) -> torch.Tensor:
37
36
  alpha, scale = (
38
37
  1.6732632423543772848170429916717,
39
38
  1.0507009873554804934193349852946,
40
39
  )
41
- # ELU is x on the positive side, so this equals the where(x > 0, x * scale,
42
- # elu) form bit for bit, without its zero-filled where backward. The
43
- # factor is at least float32, like the scalar multiply's compute type.
44
- one = x.new_ones((), dtype=torch.promote_types(x.dtype, torch.float32))
45
- factor = torch.where(x > 0, one * scale, one)
46
- return (F.elu(x, alpha * scale) * factor).to(x.dtype)
40
+ return torch.where(x > 0, x * scale, F.elu(x, alpha * scale))
47
41
 
48
42
 
49
43
  class BrainTokenizer(EEGModuleMixin, nn.Module, license="mit"):
@@ -869,13 +863,9 @@ class _SEANetConv1d(nn.Module):
869
863
  extra = (kernel_size - padding_total - x.shape[-1]) % stride
870
864
  right = padding_total // 2
871
865
  padding = (padding_total - right, right + extra)
872
- if max(padding) == 0: # 1x1 convs: padding would only copy x
873
- return self.conv(x)
874
866
  # Zero-extend a signal too short to reflect, as EnCodec does.
875
867
  short = max(max(padding) - x.shape[-1] + 1, 0)
876
- if short > 0: # F.pad with nothing to pad still copies x
877
- x = F.pad(x, (0, short))
878
- x = F.pad(x, padding, mode="reflect")
868
+ x = F.pad(F.pad(x, (0, short)), padding, mode="reflect")
879
869
  return self.conv(x[..., : x.shape[-1] - short])
880
870
 
881
871
 
@@ -15,7 +15,6 @@ from torch import nn
15
15
  from torch.nn.utils.parametrizations import weight_norm
16
16
 
17
17
  from braindecode.functional import spectral_input
18
- from braindecode.functional.functions import _next_fast_len
19
18
  from braindecode.models.base import EEGModuleMixin
20
19
 
21
20
 
@@ -522,21 +521,16 @@ class _GConv(nn.Module):
522
521
  kernel = F.pad(k_fwd, (0, seq_len)) + F.pad(k_bwd.flip(-1), (seq_len, 0))
523
522
 
524
523
  # FFT-based convolution: O(N log N)
525
- # The bidirectional kernel is circular (lags 0..L-1, then -L..-1).
526
- # Rolled to lags -L..L-1 it is a linear convolution read from lag 0,
527
- # so any FFT length >= 2 * seq_len works: take a 5-smooth (fast) one.
528
- start = seq_len if self.bidirectional else 0
529
- n_fft = 2 * _next_fast_len(seq_len)
530
524
  # kernel_freq: (channels, d_model, freq_bins)
531
525
  # spectral_input(x) dtype: x's, at least float32 (the reference's .float()).
532
526
  x_in = spectral_input(x)
533
- kernel_freq = torch.fft.rfft(kernel.roll(start, -1).to(x_in), n=n_fft)
527
+ kernel_freq = torch.fft.rfft(kernel.to(x_in), n=2 * seq_len)
534
528
  # x_freq: (batch, d_model, freq_bins)
535
- x_freq = torch.fft.rfft(x_in, n=n_fft)
529
+ x_freq = torch.fft.rfft(x_in, n=2 * seq_len)
536
530
  # out_freq: (batch, channels, d_model, freq_bins)
537
531
  out_freq = torch.einsum("bhl,chl->bchl", x_freq, kernel_freq)
538
532
  # out: (batch, channels, d_model, seq_len)
539
- out = torch.fft.irfft(out_freq, n=n_fft)[..., start : start + seq_len].to(x)
533
+ out = torch.fft.irfft(out_freq, n=2 * seq_len)[..., :seq_len].to(x)
540
534
 
541
535
  # Skip connection via learnable D matrix
542
536
  # (batch, channels, d_model, seq_len)
@@ -4,7 +4,7 @@ import torch
4
4
  import torch.nn as nn
5
5
  from mne.utils import warn
6
6
 
7
- from braindecode.functional import _real_dft, spectral_input
7
+ from braindecode.functional import spectral_input
8
8
  from braindecode.models.base import EEGModuleMixin
9
9
  from braindecode.models.util import _disable_batch_norm_training_if_batch_size_one
10
10
 
@@ -297,8 +297,6 @@ class _STFTModule(nn.Module):
297
297
 
298
298
  def forward(self, x: torch.Tensor) -> torch.Tensor:
299
299
  # x: (B, C, T)
300
- if _real_dft.needs_real_dft(x) and self.center and self.one_sided:
301
- return self._forward_real_dft(x).to(x)
302
300
  B, C, T = x.shape
303
301
  # flatten batch & channel into one dim
304
302
  x_flat = spectral_input(x.reshape(B * C, T))
@@ -321,23 +319,3 @@ class _STFTModule(nn.Module):
321
319
  spec = spec_flat.view(B, C, F, L)
322
320
 
323
321
  return torch.abs(spec).to(x)
324
-
325
- @torch.jit.unused
326
- @_real_dft.fp32_island
327
- def _forward_real_dft(self, x):
328
- # The magnitude above without complex tensors, on the device (Intel
329
- # Gaudi / HPU), instead of a host STFT and a host-to-device copy of
330
- # the whole spectrogram: reflect-padded frames (gathered, not a
331
- # strided unfold) times the one-sided DFT basis. No annotations: with
332
- # postponed annotations torch.jit.unused cannot resolve them.
333
- pad = self.n_fft // 2
334
- x = nn.functional.pad(x, (pad, pad), mode="reflect")
335
- n_frames = 1 + (x.shape[-1] - self.n_fft) // self.hop_length
336
- starts = torch.arange(n_frames, device=x.device) * self.hop_length
337
- index = (starts[:, None] + torch.arange(self.n_fft, device=x.device)).flatten()
338
- frames = x.index_select(-1, index).unflatten(-1, (n_frames, self.n_fft))
339
- real, imag = _real_dft.real_rfft(frames)
340
- magnitude = torch.sqrt(real * real + imag * imag)
341
- if self.normalized:
342
- magnitude = magnitude / self.n_fft**0.5
343
- return magnitude.transpose(-1, -2)
@@ -314,11 +314,6 @@ class CSBrain(EEGModuleMixin, nn.Module):
314
314
  sfreq=sfreq,
315
315
  )
316
316
  del n_chans, chs_info, n_times, input_window_seconds, sfreq, n_outputs
317
- n_times = self._n_times_or_none()
318
- if n_times is not None and n_times % patch_size:
319
- raise ValueError(
320
- f"n_times ({n_times}) must be a multiple of patch_size ({patch_size})."
321
- )
322
317
 
323
318
  self.rearrange = Rearrange(
324
319
  "batch n_chans (n_patch patch_size) -> batch n_chans n_patch patch_size",
@@ -541,7 +536,6 @@ class _RegionEmbedding(nn.Module):
541
536
  """
542
537
 
543
538
  region_bounds: List[Tuple[int, int]]
544
- tap_starts: List[int]
545
539
 
546
540
  def __init__(
547
541
  self,
@@ -575,61 +569,42 @@ class _RegionEmbedding(nn.Module):
575
569
  for region_key in area_config
576
570
  }
577
571
  )
578
- # All regions in one pass: tap j of the widest kernel reads, for every
579
- # electrode, the electrode at offset j - half on its region's ring
580
- # (circular padding), or nothing (zero padding of a one-electrode
581
- # region); kernel k uses the middle k taps. As a 0/1 matrix, so the
582
- # gather and its backward are matmuls.
583
- half = (max(kernel_sizes) - 1) // 2
584
- n_taps = 2 * half + 1
585
- self.tap_starts = [half - (k - 1) // 2 for k in kernel_sizes]
586
- n_chans = self.region_bounds[-1][1] if self.region_bounds else 0
587
- chan_region = []
588
- tap_select = torch.zeros(n_chans * n_taps, n_chans)
589
- for i, (start, stop) in enumerate(self.region_bounds):
590
- n = stop - start
591
- for p in range(n):
592
- chan_region.append(i)
593
- for d in range(-half, half + 1) if n > 1 else [0]:
594
- row = (start + p) * n_taps + d + half
595
- tap_select[row, start + (p + d) % n] = 1.0
596
- self.register_buffer(
597
- "chan_region", torch.tensor(chan_region, dtype=torch.long), False
598
- )
599
- self.register_buffer("tap_select", tap_select, False)
600
572
 
601
573
  def forward(self, x):
602
574
  batch, chans, T, dim_in = x.shape
603
- if len(self.region_bounds) == 0:
604
- return torch.zeros(
605
- (batch, chans, T, self.dim_out), device=x.device, dtype=x.dtype
575
+ output = torch.zeros(
576
+ (batch, chans, T, self.dim_out), device=x.device, dtype=x.dtype
577
+ )
578
+ for i, blocks in enumerate(self.region_blocks.values()):
579
+ start, stop = self.region_bounds[i]
580
+ n_electrodes = stop - start
581
+ x_region = x[:, start:stop, :, :]
582
+ x_trans = (
583
+ x_region.permute(0, 2, 1, 3)
584
+ .reshape(-1, n_electrodes, dim_in)
585
+ .permute(0, 2, 1)
586
+ .unsqueeze(-1)
606
587
  )
607
- # (batch, chans, n_taps, T, dim_in): every electrode's ring neighbours
608
- taps = torch.matmul(self.tap_select, x.reshape(batch, chans, T * dim_in))
609
- taps = taps.reshape(batch, chans, -1, T, dim_in)
610
- # Per kernel, one batched matmul over electrodes, each with its
611
- # region's weights: (chans, batch * T, k * dim_in) @ (chans, k * dim_in, out)
612
- weights: List[List[Tensor]] = [[] for _ in self.tap_starts]
613
- biases: List[List[Tensor]] = [[] for _ in self.tap_starts]
614
- for blocks in self.region_blocks.values():
615
- for j, conv in enumerate(blocks):
616
- bias = conv.bias
617
- assert bias is not None
618
- weights[j].append(conv.weight)
619
- biases[j].append(bias)
620
- outs = []
621
- for j, start in enumerate(self.tap_starts):
622
- w = torch.stack(weights[j]).index_select(0, self.chan_region)
623
- k = w.shape[3]
624
- w = w.squeeze(-1).permute(0, 3, 2, 1).reshape(chans, k * dim_in, -1)
625
- t = taps[:, :, start : start + k].permute(1, 0, 3, 2, 4)
626
- b = torch.stack(biases[j]).index_select(0, self.chan_region)
627
- outs.append(
628
- torch.bmm(t.reshape(chans, batch * T, k * dim_in), w) + b.unsqueeze(1)
588
+ fmap_outputs = []
589
+ for conv in blocks:
590
+ k = conv.kernel_size[0]
591
+ pad = (k - 1) // 2
592
+ if n_electrodes == 1:
593
+ x_padded = F.pad(
594
+ x_trans, (0, 0, pad, pad), mode="constant", value=0.0
595
+ )
596
+ else:
597
+ x_padded = F.pad(x_trans, (0, 0, pad, pad), mode="circular")
598
+ fmap_outputs.append(conv(x_padded))
599
+ fmap_cat = torch.cat(fmap_outputs, dim=1)
600
+ fmap_out = (
601
+ fmap_cat.squeeze(-1)
602
+ .permute(0, 2, 1)
603
+ .reshape(batch, T, n_electrodes, self.dim_out)
604
+ .permute(0, 2, 1, 3)
629
605
  )
630
- out = torch.cat(outs, dim=-1).view(chans, batch, T, self.dim_out)
631
- # contiguous: the residual sum keeps this layout and the next layer views it
632
- return out.permute(1, 0, 2, 3).contiguous()
606
+ output[:, start:stop, :, :] = fmap_out
607
+ return output
633
608
 
634
609
 
635
610
  class _CSBrainEncoderLayer(nn.Module):
@@ -695,17 +670,6 @@ class _CSBrainEncoderLayer(nn.Module):
695
670
  )
696
671
  else:
697
672
  self.region_attn_mask = None
698
- # Region of every electrode and electrodes per region, for the
699
- # region means of all regions at once (index_add_ sums in channel
700
- # order, as the per-region mean did).
701
- sizes = [stop - start for start, stop in self.region_bounds]
702
- chan_region = [i for i, n in enumerate(sizes) for _ in range(n)]
703
- self.register_buffer(
704
- "chan_region", torch.tensor(chan_region, dtype=torch.long), False
705
- )
706
- self.register_buffer(
707
- "region_sizes", torch.tensor(sizes, dtype=torch.long)[:, None], False
708
- )
709
673
 
710
674
  def forward(self, src: Tensor) -> Tensor:
711
675
  x = src
@@ -742,13 +706,11 @@ class _CSBrainEncoderLayer(nn.Module):
742
706
  def _inter_region_attention(self, x: Tensor) -> Tensor:
743
707
  batch, chans, T, Fea = x.shape
744
708
  x_flat = x.permute(0, 2, 1, 3).reshape(batch * T, chans, Fea)
745
- if len(self.region_bounds) == 0:
746
- global_features = torch.zeros_like(x_flat)
747
- else:
748
- region_sum = x_flat.new_zeros(batch * T, len(self.region_bounds), Fea)
749
- region_sum.index_add_(1, self.chan_region, x_flat)
750
- region_mean = region_sum / self.region_sizes
751
- global_features = region_mean.index_select(1, self.chan_region)
709
+ global_features = torch.zeros_like(x_flat)
710
+ for start, stop in self.region_bounds:
711
+ region_global = x[:, start:stop, :, :].mean(dim=1, keepdim=True)
712
+ region_global = region_global.permute(0, 2, 1, 3).reshape(batch * T, 1, Fea)
713
+ global_features[:, start:stop, :] = region_global
752
714
  x_enhanced = x_flat + self.global_fc(global_features)
753
715
 
754
716
  attn_output = self.inter_region_attn(
@@ -170,10 +170,6 @@ class Deep4Net(EEGModuleMixin, nn.Sequential):
170
170
  ):
171
171
  resolved_n_times = round(self._input_window_seconds * self._sfreq)
172
172
 
173
- if resolved_n_times is not None and resolved_n_times >= min_n_times:
174
- # The bound above ignores stride_before_pool and an integer
175
- # final_conv_length; inputs it admits are checked with the exact one.
176
- min_n_times = self._get_min_n_times(exact=True)
177
173
  if resolved_n_times is not None and resolved_n_times < min_n_times:
178
174
  scaling_factor = resolved_n_times / min_n_times
179
175
  warn(
@@ -367,15 +363,13 @@ class Deep4Net(EEGModuleMixin, nn.Sequential):
367
363
 
368
364
  self.train()
369
365
 
370
- def _get_min_n_times(self, exact: bool = False) -> int:
366
+ def _get_min_n_times(self) -> int:
371
367
  """
372
368
  Calculate the minimum number of time samples required for the model
373
369
  to work with the given temporal parameters.
374
370
  """
375
371
  # Start with the minimum valid output length of the network (1)
376
372
  min_len = 1
377
- if exact and isinstance(self.final_conv_length, int):
378
- min_len = self.final_conv_length
379
373
 
380
374
  # List of conv kernel sizes and pool parameters for the 4 blocks, in reverse order
381
375
  # Each tuple: (filter_length, pool_length, pool_stride)
@@ -388,9 +382,6 @@ class Deep4Net(EEGModuleMixin, nn.Sequential):
388
382
 
389
383
  # Work backward from the last layer to the input
390
384
  for filter_len, pool_len, pool_stride in block_params:
391
- if exact and self.stride_before_pool: # strided conv, then pool stride 1
392
- min_len = pool_stride * (min_len + pool_len - 2) + filter_len
393
- continue
394
385
  # Reverse the pooling operation
395
386
  # L_in = stride * (L_out - 1) + kernel_size
396
387
  min_len = pool_stride * (min_len - 1) + pool_len
@@ -142,11 +142,6 @@ def _build_initial_adjacency(chs_info, n_chans, n_neighbors=5):
142
142
  electrode_positions = extract_channel_locations_from_chs_info(
143
143
  chs_info, num_channels=n_chans
144
144
  )
145
- # MNE stores NaN for a channel without a position.
146
- if electrode_positions is not None and not (
147
- len(electrode_positions) == n_chans and np.isfinite(electrode_positions).all()
148
- ):
149
- electrode_positions = None
150
145
 
151
146
  if electrode_positions is None and chs_info is not None:
152
147
  # Try to infer positions from channel names via a standard montage
@@ -167,8 +162,6 @@ def _build_initial_adjacency(chs_info, n_chans, n_neighbors=5):
167
162
  "with 3-D positions or that channel names match a standard montage."
168
163
  )
169
164
 
170
- if n_chans < 2:
171
- raise ValueError("DGCNN needs at least 2 channels to build its channel graph.")
172
165
  n_neighbors_capped = min(n_neighbors, n_chans - 1)
173
166
 
174
167
  # Pairwise Euclidean distances