Braindecode 1.8.1.dev174649576__tar.gz → 1.8.1.dev174671102__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.dev174649576/braindecode.egg-info → braindecode-1.8.1.dev174671102}/PKG-INFO +1 -1
  2. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/base.py +8 -164
  3. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/tuh.py +4 -8
  4. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datautil/serialization.py +6 -10
  5. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/functional/_real_dft.py +0 -55
  6. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/functional/functions.py +13 -32
  7. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/attn_sleep.py +0 -4
  8. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/axon.py +8 -42
  9. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/barista.py +2 -2
  10. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/base.py +15 -34
  11. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/brainmodule.py +1 -13
  12. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/brainomni.py +4 -14
  13. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/codebrain.py +14 -27
  14. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/contrawr.py +1 -23
  15. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/csbrain.py +36 -74
  16. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/ctnet.py +1 -9
  17. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/deep4.py +1 -10
  18. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/dgcnn.py +0 -7
  19. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/diver1.py +59 -51
  20. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/eegconformer.py +3 -19
  21. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/eeginception_mi.py +3 -7
  22. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/eegnex.py +1 -20
  23. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/eegpt.py +9 -15
  24. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/eegsym.py +16 -68
  25. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/labram.py +15 -34
  26. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/luna.py +5 -11
  27. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/medformer.py +21 -51
  28. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/meta_neuromotor.py +8 -35
  29. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/mirepnet.py +4 -15
  30. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/msvtnet.py +2 -120
  31. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/neurorvq.py +5 -20
  32. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/neurorvq_tokenizer.py +53 -57
  33. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/patchedtransformer.py +7 -3
  34. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/reve.py +5 -29
  35. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/signal_jepa.py +4 -87
  36. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/sleep_stager_blanco_2020.py +6 -13
  37. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/tcn.py +0 -5
  38. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/tidnet.py +1 -18
  39. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/usleep.py +2 -3
  40. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/zuna.py +9 -17
  41. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/attention.py +6 -87
  42. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/dance_modules.py +3 -16
  43. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/filter.py +33 -79
  44. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/layers.py +2 -41
  45. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/quantization.py +6 -10
  46. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/preprocessing/preprocess.py +0 -11
  47. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/preprocessing/windowers.py +1 -3
  48. braindecode-1.8.1.dev174671102/braindecode/version.py +1 -0
  49. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102/braindecode.egg-info}/PKG-INFO +1 -1
  50. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/whats_new.rst +0 -77
  51. braindecode-1.8.1.dev174649576/braindecode/version.py +0 -1
  52. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/LICENSE.txt +0 -0
  53. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/MANIFEST.in +0 -0
  54. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/NOTICE.txt +0 -0
  55. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/README.rst +0 -0
  56. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/__init__.py +0 -0
  57. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/augmentation/__init__.py +0 -0
  58. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/augmentation/base.py +0 -0
  59. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/augmentation/functional.py +0 -0
  60. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/augmentation/transforms.py +0 -0
  61. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/classifier.py +0 -0
  62. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/__init__.py +0 -0
  63. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/_notebook_viewer.py +0 -0
  64. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/bbci.py +0 -0
  65. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/bcicomp.py +0 -0
  66. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/bids/__init__.py +0 -0
  67. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/bids/datasets.py +0 -0
  68. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/bids/format.py +0 -0
  69. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/bids/hub.py +0 -0
  70. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/bids/hub_format.py +0 -0
  71. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/bids/hub_io.py +0 -0
  72. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/bids/hub_validation.py +0 -0
  73. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/bids/iterable.py +0 -0
  74. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/chb_mit.py +0 -0
  75. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/collate.py +0 -0
  76. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/mne.py +0 -0
  77. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/moabb.py +0 -0
  78. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/nmt.py +0 -0
  79. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/registry.py +0 -0
  80. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/siena.py +0 -0
  81. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  82. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/sleep_physionet.py +0 -0
  83. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/utils.py +0 -0
  84. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datasets/xy.py +0 -0
  85. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datautil/__init__.py +0 -0
  86. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datautil/channel_utils.py +0 -0
  87. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datautil/hub_formats.py +0 -0
  88. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/datautil/util.py +0 -0
  89. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/eegneuralnet.py +0 -0
  90. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/functional/__init__.py +0 -0
  91. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/functional/initialization.py +0 -0
  92. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/__init__.py +0 -0
  93. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/atcnet.py +0 -0
  94. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/attentionbasenet.py +0 -0
  95. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/bendr.py +0 -0
  96. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/biot.py +0 -0
  97. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/brainbert.py +0 -0
  98. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/brant.py +0 -0
  99. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/cbramod.py +0 -0
  100. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/config.py +0 -0
  101. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/dance.py +0 -0
  102. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/deepsleepnet.py +0 -0
  103. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/eeg_clip.py +0 -0
  104. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/eegdino.py +0 -0
  105. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/eeginception_erp.py +0 -0
  106. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/eegitnet.py +0 -0
  107. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/eegminer.py +0 -0
  108. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/eegnet.py +0 -0
  109. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/eegsimpleconv.py +0 -0
  110. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/eegtcnet.py +0 -0
  111. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/emg2qwerty.py +0 -0
  112. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/fbcnet.py +0 -0
  113. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/fblightconvnet.py +0 -0
  114. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/fbmsnet.py +0 -0
  115. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/guetschel2026.py +0 -0
  116. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/hybrid.py +0 -0
  117. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/ifnet.py +0 -0
  118. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/mapa.py +0 -0
  119. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/mscformer.py +0 -0
  120. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/mvpformer.py +0 -0
  121. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/neuropose.py +0 -0
  122. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/popt.py +0 -0
  123. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/sccnet.py +0 -0
  124. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/seizure_transformer.py +0 -0
  125. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/sensingdynamics.py +0 -0
  126. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/shallow_fbcsp.py +0 -0
  127. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/sinc_shallow.py +0 -0
  128. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  129. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/sleepfm.py +0 -0
  130. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/sparcnet.py +0 -0
  131. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/sstdpn.py +0 -0
  132. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/steegformer.py +0 -0
  133. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/summary.csv +0 -0
  134. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/syncnet.py +0 -0
  135. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/tcformer.py +0 -0
  136. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/tfm_tokenizer.py +0 -0
  137. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/tmsanet.py +0 -0
  138. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/tsinception.py +0 -0
  139. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/util.py +0 -0
  140. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/models/vemg2pose.py +0 -0
  141. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/__init__.py +0 -0
  142. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/activation.py +0 -0
  143. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/blocks.py +0 -0
  144. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/channels.py +0 -0
  145. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/convolution.py +0 -0
  146. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/linear.py +0 -0
  147. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/linear_attention.py +0 -0
  148. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/parametrization.py +0 -0
  149. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/popt_modules.py +0 -0
  150. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/stats.py +0 -0
  151. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/util.py +0 -0
  152. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/modules/wrapper.py +0 -0
  153. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/preprocessing/__init__.py +0 -0
  154. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
  155. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/preprocessing/mne_preprocess.py +0 -0
  156. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/preprocessing/util.py +0 -0
  157. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/regressor.py +0 -0
  158. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/samplers/__init__.py +0 -0
  159. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/samplers/base.py +0 -0
  160. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/samplers/ssl.py +0 -0
  161. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/training/__init__.py +0 -0
  162. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/training/callbacks.py +0 -0
  163. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/training/losses.py +0 -0
  164. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/training/scoring.py +0 -0
  165. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/util.py +0 -0
  166. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/visualization/__init__.py +0 -0
  167. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/visualization/activations.py +0 -0
  168. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/visualization/attribution.py +0 -0
  169. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/visualization/confusion_matrices.py +0 -0
  170. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/visualization/frequency.py +0 -0
  171. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/visualization/metrics.py +0 -0
  172. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/visualization/sanity.py +0 -0
  173. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode/visualization/topology.py +0 -0
  174. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode.egg-info/SOURCES.txt +0 -0
  175. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode.egg-info/dependency_links.txt +0 -0
  176. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode.egg-info/requires.txt +0 -0
  177. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/braindecode.egg-info/top_level.txt +0 -0
  178. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/Makefile +0 -0
  179. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/_templates/autosummary/class.rst +0 -0
  180. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  181. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/_templates/autosummary/function.rst +0 -0
  182. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  183. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/agent_docs.rst +0 -0
  184. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/api.rst +0 -0
  185. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/cite.rst +0 -0
  186. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/conf.py +0 -0
  187. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/help.rst +0 -0
  188. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/index.rst +0 -0
  189. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/install/install.rst +0 -0
  190. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/install/install_pip.rst +0 -0
  191. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/install/install_source.rst +0 -0
  192. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/models/categorization/attention.rst +0 -0
  193. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/models/categorization/channel.rst +0 -0
  194. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/models/categorization/convolution.rst +0 -0
  195. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/models/categorization/filterbank.rst +0 -0
  196. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/models/categorization/gnn.rst +0 -0
  197. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/models/categorization/interpretable.rst +0 -0
  198. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/models/categorization/lbm.rst +0 -0
  199. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/models/categorization/recurrent.rst +0 -0
  200. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/models/categorization/spd.rst +0 -0
  201. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/models/models.rst +0 -0
  202. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/models/models_categorization.rst +0 -0
  203. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/models/models_table.rst +0 -0
  204. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/models/models_visualization.rst +0 -0
  205. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/sg_execution_times.rst +0 -0
  206. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/docs/user_guide/channel_strategies.rst +0 -0
  207. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/pyproject.toml +0 -0
  208. {braindecode-1.8.1.dev174649576 → braindecode-1.8.1.dev174671102}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.8.1.dev174649576
3
+ Version: 1.8.1.dev174671102
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,125 +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, willneed=False):
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
- With ``willneed=True`` nothing is read and None is returned: the OS is
295
- only asked to start reading the window's bytes into the page cache in the
296
- background (``posix_fadvise(POSIX_FADV_WILLNEED)``).
297
- """
298
- if (
299
- not isinstance(raw, mne.io.Raw)
300
- or raw.preload
301
- or len(raw._raw_extras) != 1
302
- or raw._projector is not None
303
- or raw._comp is not None
304
- ):
305
- return None
306
- extra = raw._raw_extras[0]
307
- fname, bounds = extra["filename"], extra["bounds"]
308
- if not isinstance(fname, Path) or fname.suffix == ".gz":
309
- return None
310
- start, stop = start + raw._first_samps[0], stop + raw._first_samps[0]
311
- first = np.searchsorted(bounds, start, side="right") - 1
312
- tags = extra["ent"]
313
- if isinstance(tags, _FifTagTable):
314
- rows = tags.table[first : np.searchsorted(bounds, stop)]
315
- else:
316
- tags = tags[first : np.searchsorted(bounds, stop)]
317
- if any(t is None for t in tags):
318
- return None
319
- rows = _tag_rows(tags)
320
- if not len(rows) or (rows[:, 1] != FIFF.FIFFT_FLOAT).any():
321
- return None
322
- size, pos = rows[:, 2].tolist(), rows[:, 4].tolist()
323
- if willneed: # only a hint: any error is left to the read itself
324
- try:
325
- with open(fname, "rb") as f:
326
- os.posix_fadvise(
327
- f.fileno(),
328
- pos[0],
329
- pos[-1] + 16 + size[-1] - pos[0],
330
- os.POSIX_FADV_WILLNEED,
331
- )
332
- except OSError:
333
- pass
334
- return None
335
- # mmap: no copy through a 4 MB read buffer, and a cold file is read around
336
- # the window by the kernel (as mne's 4 MB reads did), not window by window
337
- with open(fname, "rb") as f, mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as m:
338
- buf = m[pos[0] : pos[-1] + 16 + size[-1]]
339
- one = np.concatenate(
340
- [np.frombuffer(buf, ">f4", s // 4, p + 16 - pos[0]) for s, p in zip(size, pos)]
341
- ).reshape(-1, extra["orig_nchan"])[start - bounds[first] : stop - bounds[first]]
342
- picked = one[:, raw._read_picks[0]].T
343
- return np.multiply(picked, raw._cals[:, np.newaxis], order="C")
344
-
345
-
346
223
  def _window_info(crop_inds, sfreq):
347
224
  """Extract window size from crop indices.
348
225
 
@@ -946,11 +823,9 @@ class EEGWindowsDataset(_ZarrMixin, RecordDataset):
946
823
  if self._zarr_data is not None:
947
824
  X = self._zarr_data[:, i_start:i_stop]
948
825
  else:
949
- X = _read_fif_window(self.raw, i_start, i_stop)
950
- if X is None:
951
- X = self.raw._getitem(
952
- (slice(None), slice(i_start, i_stop)), return_times=False
953
- )
826
+ X = self.raw._getitem(
827
+ (slice(None), slice(i_start, i_stop)), return_times=False
828
+ )
954
829
  X = np.array(X, dtype="float32")
955
830
  if self.transform is not None:
956
831
  X = self.transform(X)
@@ -1378,8 +1253,7 @@ class BaseConcatDataset(ConcatDataset, HubDatasetMixin, Generic[T]):
1378
1253
  def __len__(self):
1379
1254
  return self._ensure_cumulative_sizes()[-1]
1380
1255
 
1381
- def _locate(self, idx: int):
1382
- """The dataset that holds item ``idx`` and the item's index in it."""
1256
+ def _get_single_item(self, idx: int):
1383
1257
  if idx < 0:
1384
1258
  if -idx > len(self):
1385
1259
  raise ValueError(
@@ -1393,33 +1267,7 @@ class BaseConcatDataset(ConcatDataset, HubDatasetMixin, Generic[T]):
1393
1267
  sample_idx = idx
1394
1268
  else:
1395
1269
  sample_idx = idx - cumulative_sizes[dataset_idx - 1]
1396
- return self.datasets[dataset_idx], sample_idx
1397
-
1398
- def _get_single_item(self, idx: int):
1399
- ds, i = self._locate(idx)
1400
- return ds[i]
1401
-
1402
- def __getitems__(self, indices):
1403
- """Items ``indices``, as ``[self[i] for i in indices]``.
1404
-
1405
- A :class:`~torch.utils.data.DataLoader` fetches each batch through
1406
- this. The lazy FIF windows of the batch are first requested from the
1407
- OS all at once (``posix_fadvise(POSIX_FADV_WILLNEED)``, where it
1408
- exists), so their reads from disk overlap instead of running one after
1409
- another: on a network file system a batch read from cold files then
1410
- costs about one round trip, not one per window.
1411
- """
1412
- # ponytail: advises the whole batch at once; chunk it if a batch's
1413
- # windows ever outgrow the page cache
1414
- if hasattr(os, "posix_fadvise"):
1415
- for idx in indices:
1416
- if not isinstance(idx, (int, np.integer)):
1417
- continue # e.g. a SequenceSampler tuple: read, not advised
1418
- ds, i = self._locate(idx)
1419
- if isinstance(ds, EEGWindowsDataset) and ds._zarr_data is None:
1420
- _, start, stop = ds.crop_inds[i].tolist()
1421
- _read_fif_window(ds.raw, start, stop, willneed=True)
1422
- return [self[idx] for idx in indices]
1270
+ return self.datasets[dataset_idx][sample_idx]
1423
1271
 
1424
1272
  def __getitem__(self, idx: int | list):
1425
1273
  """
@@ -1824,8 +1672,7 @@ class BaseConcatDataset(ConcatDataset, HubDatasetMixin, Generic[T]):
1824
1672
  kwargs_path = os.path.join(path, ".".join([kwarg_name, "json"]))
1825
1673
  kwargs = getattr(self, kwarg_name)
1826
1674
  if kwargs is not None:
1827
- with open(kwargs_path, "w") as f:
1828
- json.dump(kwargs, f)
1675
+ json.dump(kwargs, open(kwargs_path, "w"))
1829
1676
 
1830
1677
  @property
1831
1678
  def description(self) -> pd.DataFrame:
@@ -1895,10 +1742,7 @@ class BaseConcatDataset(ConcatDataset, HubDatasetMixin, Generic[T]):
1895
1742
  # Create path if it doesn't exist
1896
1743
  os.makedirs(path, exist_ok=True)
1897
1744
 
1898
- # With an offset the caller fills one directory piece by piece (preprocess
1899
- # saves each recording at its index), so the other entries are expected:
1900
- # skip the scan that would stat them all on every call and list them in a warning.
1901
- path_contents = os.listdir(path) if offset == 0 else []
1745
+ path_contents = os.listdir(path)
1902
1746
  n_sub_dirs = len(
1903
1747
  [e for e in path_contents if os.path.isdir(os.path.join(path, e))]
1904
1748
  )
@@ -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):
@@ -12,10 +12,8 @@ never downcast, so callers wrap the numerically sensitive parts with
12
12
  #
13
13
  # License: BSD (3-clause)
14
14
  import functools
15
- from typing import Optional
16
15
 
17
16
  import torch
18
- from torch import nn
19
17
 
20
18
 
21
19
  def needs_real_dft(x: torch.Tensor) -> bool:
@@ -138,56 +136,3 @@ def hilbert_freq_real(x: torch.Tensor, forward_fourier: bool) -> torch.Tensor:
138
136
  return torch.stack((out_real, out_imag), dim=-1)
139
137
 
140
138
  return compute(x)
141
-
142
-
143
- @torch.jit.unused
144
- def fft_conv1d_real(
145
- x: torch.Tensor, weight: torch.Tensor, bias: Optional[torch.Tensor]
146
- ) -> torch.Tensor:
147
- """Real-valued equivalent of :func:`braindecode.functional.fft_conv1d`.
148
-
149
- Overlap-save: the input is cut into blocks of ``n`` samples (the power of
150
- two ``>= 2 * kernel_size``) that advance by ``n - kernel_size + 1`` outputs,
151
- each block's DFT is a matmul against the cosine/sine basis, and per
152
- frequency the complex product with the kernels, summed over the input
153
- channels, is one real matmul.
154
- """
155
-
156
- @fp32_island
157
- def compute(x, weight):
158
- n_times, kernel_size = x.shape[-1], weight.shape[-1]
159
- n = 1 << (2 * kernel_size - 1).bit_length()
160
- hop = n - kernel_size + 1
161
- n_blocks = -(-n_times // hop)
162
- n_freqs = n // 2 + 1
163
- # "same" alignment: torch pads the extra zero of an even kernel on the right
164
- left = (kernel_size - 1) // 2
165
- x = nn.functional.pad(x, (left, (n_blocks + 1) * hop - n_times - left))
166
- hops = x.unflatten(-1, (n_blocks + 1, hop))
167
- # block i = hop i + the first kernel_size - 1 samples of hop i + 1
168
- blocks = torch.cat([hops[:, :, :-1], hops[:, :, 1:, : kernel_size - 1]], -1)
169
- cosine, sine = real_dft_basis(n, device=x.device, dtype=x.dtype)
170
- basis = torch.cat([cosine, -sine]).transpose(0, 1) # -> [Re | Im] of rfft
171
- x_f = blocks @ basis # (batch, in, blocks, 2 * n_freqs)
172
- w_f = nn.functional.pad(weight.to(x), (0, n - kernel_size)) @ basis
173
- w_re, w_im = w_f[..., :n_freqs], w_f[..., n_freqs:]
174
- # conv1d is a cross-correlation: x_f * conj(w_f), summed over the input
175
- # channels. Per frequency [Re x, Im x] @ [[Re w, -Im w], [Im w, Re w]].
176
- w_f = torch.cat([torch.cat([w_re, -w_im]), torch.cat([w_im, w_re])], 1)
177
- x_f = x_f.unflatten(-1, (2, n_freqs)).permute(4, 0, 2, 3, 1).flatten(1, 2)
178
- y_f = torch.bmm(x_f.flatten(2), w_f.permute(2, 1, 0)) # (freq, ., 2 * out)
179
- y_f = y_f.unflatten(1, (x.shape[0], n_blocks)).unflatten(-1, (2, -1))
180
- y_f = y_f.permute(1, 4, 2, 3, 0).flatten(
181
- -2
182
- ) # (batch, out, blocks, 2 * n_freqs)
183
- # inverse DFT of the first `hop` samples, the ones without wrap-around
184
- scale = torch.full((n_freqs, 1), 2.0 / n, dtype=x.dtype, device=x.device)
185
- scale[0] = 1.0 / n
186
- scale[-1] = 1.0 / n # Nyquist (n is even)
187
- inverse = torch.cat([scale * cosine[:, :hop], -scale * sine[:, :hop]])
188
- return (y_f @ inverse).flatten(-2)[..., :n_times]
189
-
190
- y = compute(x, weight)
191
- if bias is not None:
192
- y = y + bias.to(y).unsqueeze(-1)
193
- return y.to(x)
@@ -62,10 +62,9 @@ def fft_conv1d(
62
62
 
63
63
  Equal to the direct convolution up to float rounding: the FFT is long
64
64
  enough for a linear (not circular) convolution. Its cost barely grows with
65
- the kernel size, so it is faster than the direct one for long kernels
66
- (see :func:`prefer_fft_conv`). float16/bfloat16 inputs are computed in
67
- float32 (:func:`spectral_input`) and cast back. On Intel Gaudi (HPU, no
68
- complex dtype) the DFTs are real matmuls over overlapping blocks.
65
+ the kernel size, so it is faster than the direct one for long kernels on
66
+ CPU (see :func:`prefer_fft_conv`). float16/bfloat16 inputs are computed in
67
+ float32 (:func:`spectral_input`) and cast back.
69
68
 
70
69
  Parameters
71
70
  ----------
@@ -83,35 +82,22 @@ def fft_conv1d(
83
82
  ``x``. For an even ``kernel_size`` it is aligned like torch's
84
83
  ``padding="same"`` (the extra zero padded on the right).
85
84
  """
86
- if _real_dft.needs_real_dft(x):
87
- return _real_dft.fft_conv1d_real(x, weight, bias)
88
85
  n_times, kernel_size = x.shape[-1], weight.shape[-1]
89
86
  # >= n_times + kernel_size - 1 (no circular wrap-around), even and
90
87
  # 5-smooth: the fast cases of a real FFT
91
88
  n_fft = 2 * _next_fast_len((n_times + kernel_size) // 2)
92
89
  xs = spectral_input(x)
93
90
  # conv1d is a cross-correlation: a convolution with the flipped kernel
94
- x_f = torch.fft.rfft(xs, n=n_fft) # (batch, in, freq)
91
+ x_f = torch.fft.rfft(xs, n=n_fft).permute(2, 0, 1) # (freq, batch, in)
95
92
  w_f = torch.fft.rfft(weight.to(xs).flip(-1), n=n_fft).permute(2, 1, 0)
96
93
  # Per frequency (batch, in) @ (in, out) in complex numbers, as one real
97
- # matmul (a complex one is slower on CPU).
98
- needs_grad = torch.is_grad_enabled() and (x.requires_grad or weight.requires_grad)
99
- if needs_grad or x.shape[0] >= 2 * x.shape[1]:
100
- # [Re x, Im x] @ [[Re w, Im w], [-Im w, Re w]] (rows of i * w): the
101
- # output columns are the (Re, Im) pairs of the result, read as complex
102
- # without a copy (and without a costly backward).
103
- w_mat = torch.view_as_real(torch.stack([w_f, w_f * 1j], 1)).flatten(1, 2)
104
- y_f = torch.view_as_real(x_f).permute(2, 0, 3, 1).flatten(2) @ w_mat.flatten(2)
105
- y_f = torch.view_as_complex(y_f.unflatten(-1, [-1, 2]))
106
- else:
107
- # Forward only with fewer rows than twice the input channels: the
108
- # doubled weight costs more than combining [Re x; Im x] @ [Re w, Im w].
109
- x_f = x_f.permute(2, 0, 1)
110
- p = torch.cat([x_f.real, x_f.imag], 1) @ torch.view_as_real(w_f).flatten(2)
111
- p = p.unflatten(1, [2, x.shape[0]]).unflatten(3, [-1, 2])
112
- y_f = torch.complex(
113
- p[:, 0, :, :, 0] - p[:, 1, :, :, 1], p[:, 0, :, :, 1] + p[:, 1, :, :, 0]
114
- )
94
+ # matmul (a complex one is slower on CPU): [Re x; Im x] @ [Re w, Im w]
95
+ # (columns interleaved) holds the four real products.
96
+ p = torch.cat([x_f.real, x_f.imag], 1) @ torch.view_as_real(w_f).flatten(2)
97
+ p = p.unflatten(1, [2, x.shape[0]]).unflatten(3, [-1, 2]) # x re/im, w re/im
98
+ y_f = torch.complex(
99
+ p[:, 0, :, :, 0] - p[:, 1, :, :, 1], p[:, 0, :, :, 1] + p[:, 1, :, :, 0]
100
+ )
115
101
  y = torch.fft.irfft(y_f.permute(1, 2, 0), n=n_fft)
116
102
  # "same" output t is sample t + kernel_size // 2 of the full convolution
117
103
  y = y[..., kernel_size // 2 : kernel_size // 2 + n_times]
@@ -129,11 +115,8 @@ def prefer_fft_conv(x: torch.Tensor, kernel_size: int) -> bool:
129
115
  and from ``batch_size * kernel_size >= 600`` if also
130
116
  ``in_channels * kernel_size >= 120``: with one or two input channels a
131
117
  float32 direct convolution stays cheaper up to k = 85 / 31 (13 long
132
- temporal convolutions of the model zoo, 22 channels x batch 32). On Intel
133
- Gaudi (HPU) a direct convolution costs about ``batch_size * n_times *
134
- kernel_size`` and the FFT about a fixed few milliseconds in eager mode: the
135
- FFT wins from 8 input channels and ``batch_size * n_times * kernel_size >=
136
- 8e6``. GPUs keep the direct convolution.
118
+ temporal convolutions of the model zoo, 22 channels x batch 32). GPUs and
119
+ HPUs (no complex dtype) keep the direct convolution.
137
120
 
138
121
  Parameters
139
122
  ----------
@@ -142,8 +125,6 @@ def prefer_fft_conv(x: torch.Tensor, kernel_size: int) -> bool:
142
125
  kernel_size : int
143
126
  Kernel length in samples.
144
127
  """
145
- if x.device.type == "hpu":
146
- return x.shape[1] >= 8 and x.shape[0] * x.shape[-1] * kernel_size >= 8e6
147
128
  return x.device.type == "cpu" and (
148
129
  x.element_size() == 2
149
130
  or (x.shape[0] * kernel_size >= 600 and x.shape[1] * kernel_size >= 120)
@@ -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",
@@ -14,7 +14,6 @@ from torch import nn
14
14
  from braindecode.functional import sinusoidal_positional_encoding
15
15
  from braindecode.models.base import EEGModuleMixin
16
16
  from braindecode.models.util import warn_if_sfreq_differs
17
- from braindecode.modules.attention import _scaled_dot_product_attention
18
17
  from braindecode.modules.channels import _resolve
19
18
 
20
19
 
@@ -463,33 +462,11 @@ class _AxisAttention(nn.Module):
463
462
  .unbind(0)
464
463
  )
465
464
  drop = self.att_drop_prob if self.training else 0.0
466
- attended = _scaled_dot_product_attention(
465
+ attended = F.scaled_dot_product_attention(
467
466
  query, key, value, attn_mask=mask, dropout_p=drop
468
467
  )
469
468
  return attended.transpose(1, 2).reshape(n_seq, length, -1)
470
469
 
471
- def _attend_two_scales(
472
- self, projected: torch.Tensor, band: torch.Tensor, weights: torch.Tensor
473
- ) -> torch.Tensor:
474
- """Banded and full attention from one score matrix, mixed per query.
475
-
476
- ``weights`` (N, L, 2) are the scale-gate weights. Both softmaxes share
477
- the scores and one product with the values serves the mixture.
478
- """
479
- n_seq, length, _ = projected.shape
480
- query, key, value = (
481
- projected.reshape(n_seq, length, 3, self.num_heads, self.head_dim)
482
- .permute(2, 0, 3, 1, 4)
483
- .unbind(0)
484
- )
485
- scores = torch.matmul(query, key.transpose(-2, -1)) * self.head_dim**-0.5
486
- weights = weights.reshape(n_seq, 1, length, 2)
487
- probs = weights[..., 0:1] * scores.masked_fill(~band, float("-inf")).softmax(
488
- -1
489
- ) + weights[..., 1:2] * scores.softmax(-1)
490
- attended = torch.matmul(probs, value)
491
- return attended.transpose(1, 2).reshape(n_seq, length, -1)
492
-
493
470
  def forward(self, x: torch.Tensor, band: Optional[torch.Tensor]) -> torch.Tensor:
494
471
  batch, n_chans, n_patches, dim = x.shape
495
472
  axis_weights = self.axis_gate(x) # (B, C, P, 2)
@@ -499,26 +476,15 @@ class _AxisAttention(nn.Module):
499
476
  # the restricted branch is the full one; attend once unless the two
500
477
  # branches draw their own attention dropout.
501
478
  per_channel = self.temporal_qkv(x.reshape(batch * n_chans, n_patches, dim))
502
- dropout = self.training and self.att_drop_prob > 0
503
- if band is not None and not dropout:
504
- # The scale-gate weights sum to one, so the two branches share the
505
- # scores, the product with the values and temporal_out.
506
- attended = self._attend_two_scales(per_channel, band, scale_weights)
507
- temporal = self.temporal_out(attended).reshape(
508
- batch, n_chans, n_patches, dim
509
- )
510
- else:
511
- restricted = self.temporal_out(self._attend(per_channel, band)).reshape(
479
+ restricted = self.temporal_out(self._attend(per_channel, band)).reshape(
480
+ batch, n_chans, n_patches, dim
481
+ )
482
+ full = restricted
483
+ if band is not None or (self.training and self.att_drop_prob > 0):
484
+ full = self.temporal_out(self._attend(per_channel, None)).reshape(
512
485
  batch, n_chans, n_patches, dim
513
486
  )
514
- full = restricted
515
- if dropout:
516
- full = self.temporal_out(self._attend(per_channel, None)).reshape(
517
- batch, n_chans, n_patches, dim
518
- )
519
- temporal = (
520
- scale_weights[..., 0:1] * restricted + scale_weights[..., 1:2] * full
521
- )
487
+ temporal = scale_weights[..., 0:1] * restricted + scale_weights[..., 1:2] * full
522
488
 
523
489
  # Spatial path: one sequence of C tokens per time step.
524
490
  per_step = self.spatial_qkv(
@@ -7,13 +7,13 @@ from __future__ import annotations
7
7
  from typing import Optional
8
8
 
9
9
  import torch
10
+ import torch.nn.functional as F
10
11
  from einops.layers.torch import Rearrange
11
12
  from torch import nn
12
13
 
13
14
  from braindecode.models.base import EEGModuleMixin
14
15
  from braindecode.models.util import extract_channel_locations_from_chs_info
15
16
  from braindecode.modules import GatedLinearUnit, PatchTokenizer
16
- from braindecode.modules.attention import _scaled_dot_product_attention
17
17
 
18
18
 
19
19
  class BaRISTA(EEGModuleMixin, nn.Module, license="other"):
@@ -689,7 +689,7 @@ class _RotarySelfAttention(nn.Module):
689
689
 
690
690
  # Dropout falls on the attention output rather than on the weights,
691
691
  # through dropout_p, because the reference disables the latter outright.
692
- attention = _scaled_dot_product_attention(query, key, value)
692
+ attention = F.scaled_dot_product_attention(query, key, value)
693
693
  attention = self.dropout(attention)
694
694
  attention = self.merge_heads(attention)
695
695
  return self.o_proj(attention)
@@ -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.