braindecode 1.8.1.dev168760068__tar.gz → 1.8.1.dev168889947__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 (207) hide show
  1. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/NOTICE.txt +3 -0
  2. {braindecode-1.8.1.dev168760068/braindecode.egg-info → braindecode-1.8.1.dev168889947}/PKG-INFO +1 -1
  3. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/augmentation/functional.py +5 -1
  4. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/functional/__init__.py +4 -0
  5. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/functional/functions.py +107 -7
  6. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/biot.py +16 -7
  7. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/brainomni.py +75 -40
  8. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/dance.py +1 -1
  9. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eeginception_mi.py +25 -94
  10. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegpt.py +47 -74
  11. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/labram.py +55 -40
  12. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/mapa.py +108 -71
  13. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/mvpformer.py +172 -191
  14. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/tfm_tokenizer.py +8 -15
  15. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/dance_modules.py +32 -23
  16. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/filter.py +3 -14
  17. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/layers.py +12 -21
  18. braindecode-1.8.1.dev168889947/braindecode/modules/linear_attention.py +128 -0
  19. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/quantization.py +40 -33
  20. braindecode-1.8.1.dev168889947/braindecode/version.py +1 -0
  21. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947/braindecode.egg-info}/PKG-INFO +1 -1
  22. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode.egg-info/SOURCES.txt +1 -0
  23. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/api.rst +2 -0
  24. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/whats_new.rst +33 -0
  25. braindecode-1.8.1.dev168760068/braindecode/version.py +0 -1
  26. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/LICENSE.txt +0 -0
  27. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/MANIFEST.in +0 -0
  28. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/README.rst +0 -0
  29. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/__init__.py +0 -0
  30. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/augmentation/__init__.py +0 -0
  31. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/augmentation/base.py +0 -0
  32. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/augmentation/transforms.py +0 -0
  33. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/classifier.py +0 -0
  34. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/__init__.py +0 -0
  35. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/_notebook_viewer.py +0 -0
  36. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/base.py +0 -0
  37. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bbci.py +0 -0
  38. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bcicomp.py +0 -0
  39. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/__init__.py +0 -0
  40. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/datasets.py +0 -0
  41. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/format.py +0 -0
  42. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/hub.py +0 -0
  43. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/hub_format.py +0 -0
  44. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/hub_io.py +0 -0
  45. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/hub_validation.py +0 -0
  46. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/iterable.py +0 -0
  47. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/chb_mit.py +0 -0
  48. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/collate.py +0 -0
  49. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/mne.py +0 -0
  50. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/moabb.py +0 -0
  51. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/nmt.py +0 -0
  52. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/registry.py +0 -0
  53. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/siena.py +0 -0
  54. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  55. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/sleep_physionet.py +0 -0
  56. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/tuh.py +0 -0
  57. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/utils.py +0 -0
  58. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/xy.py +0 -0
  59. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datautil/__init__.py +0 -0
  60. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datautil/channel_utils.py +0 -0
  61. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datautil/hub_formats.py +0 -0
  62. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datautil/serialization.py +0 -0
  63. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datautil/util.py +0 -0
  64. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/eegneuralnet.py +0 -0
  65. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/functional/_real_dft.py +0 -0
  66. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/functional/initialization.py +0 -0
  67. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/__init__.py +0 -0
  68. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/atcnet.py +0 -0
  69. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/attentionbasenet.py +0 -0
  70. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/attn_sleep.py +0 -0
  71. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/axon.py +0 -0
  72. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/barista.py +0 -0
  73. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/base.py +0 -0
  74. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/bendr.py +0 -0
  75. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/brainbert.py +0 -0
  76. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/brainmodule.py +0 -0
  77. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/brant.py +0 -0
  78. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/cbramod.py +0 -0
  79. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/codebrain.py +0 -0
  80. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/config.py +0 -0
  81. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/contrawr.py +0 -0
  82. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/csbrain.py +0 -0
  83. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/ctnet.py +0 -0
  84. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/deep4.py +0 -0
  85. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/deepsleepnet.py +0 -0
  86. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/dgcnn.py +0 -0
  87. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/diver1.py +0 -0
  88. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eeg_clip.py +0 -0
  89. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegconformer.py +0 -0
  90. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegdino.py +0 -0
  91. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eeginception_erp.py +0 -0
  92. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegitnet.py +0 -0
  93. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegminer.py +0 -0
  94. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegnet.py +0 -0
  95. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegnex.py +0 -0
  96. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegsimpleconv.py +0 -0
  97. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegsym.py +0 -0
  98. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegtcnet.py +0 -0
  99. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/emg2qwerty.py +0 -0
  100. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/fbcnet.py +0 -0
  101. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/fblightconvnet.py +0 -0
  102. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/fbmsnet.py +0 -0
  103. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/hybrid.py +0 -0
  104. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/ifnet.py +0 -0
  105. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/luna.py +0 -0
  106. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/medformer.py +0 -0
  107. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/meta_neuromotor.py +0 -0
  108. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/mirepnet.py +0 -0
  109. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/mscformer.py +0 -0
  110. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/msvtnet.py +0 -0
  111. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/neuropose.py +0 -0
  112. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/neurorvq.py +0 -0
  113. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/neurorvq_tokenizer.py +0 -0
  114. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/patchedtransformer.py +0 -0
  115. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/popt.py +0 -0
  116. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/reve.py +0 -0
  117. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sccnet.py +0 -0
  118. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/seizure_transformer.py +0 -0
  119. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sensingdynamics.py +0 -0
  120. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/shallow_fbcsp.py +0 -0
  121. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/signal_jepa.py +0 -0
  122. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sinc_shallow.py +0 -0
  123. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
  124. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  125. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sleepfm.py +0 -0
  126. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sparcnet.py +0 -0
  127. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sstdpn.py +0 -0
  128. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/steegformer.py +0 -0
  129. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/summary.csv +0 -0
  130. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/syncnet.py +0 -0
  131. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/tcformer.py +0 -0
  132. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/tcn.py +0 -0
  133. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/tidnet.py +0 -0
  134. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/tmsanet.py +0 -0
  135. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/tsinception.py +0 -0
  136. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/usleep.py +0 -0
  137. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/util.py +0 -0
  138. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/vemg2pose.py +0 -0
  139. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/zuna.py +0 -0
  140. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/__init__.py +0 -0
  141. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/activation.py +0 -0
  142. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/attention.py +0 -0
  143. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/blocks.py +0 -0
  144. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/channels.py +0 -0
  145. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/convolution.py +0 -0
  146. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/linear.py +0 -0
  147. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/parametrization.py +0 -0
  148. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/popt_modules.py +0 -0
  149. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/stats.py +0 -0
  150. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/util.py +0 -0
  151. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/wrapper.py +0 -0
  152. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/preprocessing/__init__.py +0 -0
  153. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
  154. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/preprocessing/mne_preprocess.py +0 -0
  155. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/preprocessing/preprocess.py +0 -0
  156. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/preprocessing/util.py +0 -0
  157. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/preprocessing/windowers.py +0 -0
  158. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/regressor.py +0 -0
  159. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/samplers/__init__.py +0 -0
  160. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/samplers/base.py +0 -0
  161. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/samplers/ssl.py +0 -0
  162. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/training/__init__.py +0 -0
  163. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/training/callbacks.py +0 -0
  164. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/training/losses.py +0 -0
  165. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/training/scoring.py +0 -0
  166. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/util.py +0 -0
  167. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/__init__.py +0 -0
  168. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/activations.py +0 -0
  169. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/attribution.py +0 -0
  170. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/confusion_matrices.py +0 -0
  171. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/frequency.py +0 -0
  172. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/metrics.py +0 -0
  173. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/sanity.py +0 -0
  174. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/topology.py +0 -0
  175. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode.egg-info/dependency_links.txt +0 -0
  176. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode.egg-info/requires.txt +0 -0
  177. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode.egg-info/top_level.txt +0 -0
  178. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/Makefile +0 -0
  179. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/_templates/autosummary/class.rst +0 -0
  180. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  181. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/_templates/autosummary/function.rst +0 -0
  182. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  183. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/agent_docs.rst +0 -0
  184. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/cite.rst +0 -0
  185. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/conf.py +0 -0
  186. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/help.rst +0 -0
  187. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/index.rst +0 -0
  188. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/install/install.rst +0 -0
  189. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/install/install_pip.rst +0 -0
  190. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/install/install_source.rst +0 -0
  191. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/attention.rst +0 -0
  192. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/channel.rst +0 -0
  193. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/convolution.rst +0 -0
  194. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/filterbank.rst +0 -0
  195. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/gnn.rst +0 -0
  196. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/interpretable.rst +0 -0
  197. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/lbm.rst +0 -0
  198. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/recurrent.rst +0 -0
  199. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/spd.rst +0 -0
  200. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/models.rst +0 -0
  201. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/models_categorization.rst +0 -0
  202. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/models_table.rst +0 -0
  203. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/models_visualization.rst +0 -0
  204. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/sg_execution_times.rst +0 -0
  205. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/user_guide/channel_strategies.rst +0 -0
  206. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/pyproject.toml +0 -0
  207. {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/setup.cfg +0 -0
@@ -49,6 +49,7 @@ The following components are licensed under the MIT License:
49
49
  - `braindecode/modules/popt_modules.py`
50
50
  - `braindecode/models/brainomni.py`
51
51
  - `braindecode/modules/quantization.py`
52
+ - `braindecode/modules/linear_attention.py`
52
53
  - `braindecode/models/seizure_transformer.py`
53
54
  - `docs/_static/model/seizure_transformer_arch.png`
54
55
  - `braindecode/models/tmsanet.py`
@@ -57,6 +58,8 @@ The `brainomni.py` file is a derivative of `OpenTSLab/BrainOmni` (MIT), whose
57
58
  SEANet codec derives from Meta's `facebookresearch/encodec` (MIT). The
58
59
  `quantization.py` module holds the residual vector quantization derived from
59
60
  `lucidrains/vector-quantize-pytorch` (MIT) and the BrainOmni port.
61
+ The `linear_attention.py` module is the part of
62
+ `lucidrains/linear-attention-transformer` (MIT) that BIOT and TFMTokenizer run.
60
63
 
61
64
  ### Apache-2.0 Licensed Files
62
65
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.8.1.dev168760068
3
+ Version: 1.8.1.dev168889947
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>
@@ -3,6 +3,7 @@
3
3
  # Gustavo Rodrigues <gustavenrique01@gmail.com>
4
4
  # Bruna Lopes <brunajaflopes@gmail.com>
5
5
  # Sarthak Tayal <sarthaktayal2@gmail.com>
6
+ # Anton Soloviev <anton@praviel.com>
6
7
  #
7
8
  # License: BSD (3-clause)
8
9
 
@@ -1093,7 +1094,8 @@ def segmentation_reconstruction(
1093
1094
  y : torch.Tensor
1094
1095
  EEG labels for the example or batch.
1095
1096
  n_segments : int
1096
- Number of segments to use in the batch.
1097
+ Number of segments to use in the batch. Any remaining samples are
1098
+ included in the last segment.
1097
1099
  data_classes : list[tuple[int, torch.Tensor]]
1098
1100
  List of tuples. Each tuple contains the class index and the corresponding EEG data.
1099
1101
  rand_indices : array-like
@@ -1133,6 +1135,8 @@ def segmentation_reconstruction(
1133
1135
  for idx_segment in range(n_segments):
1134
1136
  start = idx_segment * segment_size
1135
1137
  end = (idx_segment + 1) * segment_size
1138
+ if idx_segment == n_segments - 1:
1139
+ end = window_size
1136
1140
 
1137
1141
  # Perform the data augmentation
1138
1142
  X_aug[np.arange(n_trials), :, start:end] = X_class[
@@ -3,11 +3,13 @@ from .functions import (
3
3
  daubechies_filters,
4
4
  drop_path,
5
5
  dwt_max_level,
6
+ fft_conv1d,
6
7
  hilbert_freq,
7
8
  identity,
8
9
  iou_1d,
9
10
  pairwise_iou_1d,
10
11
  plv_time,
12
+ prefer_fft_conv,
11
13
  rotate_pairs,
12
14
  safe_log,
13
15
  sinusoidal_positional_encoding,
@@ -22,11 +24,13 @@ __all__ = [
22
24
  "daubechies_filters",
23
25
  "drop_path",
24
26
  "dwt_max_level",
27
+ "fft_conv1d",
25
28
  "hilbert_freq",
26
29
  "identity",
27
30
  "iou_1d",
28
31
  "pairwise_iou_1d",
29
32
  "plv_time",
33
+ "prefer_fft_conv",
30
34
  "rotate_pairs",
31
35
  "safe_log",
32
36
  "sinusoidal_positional_encoding",
@@ -7,6 +7,7 @@
7
7
  from __future__ import annotations
8
8
 
9
9
  import math
10
+ from typing import Optional
10
11
 
11
12
  import numpy as np
12
13
  import torch
@@ -54,6 +55,91 @@ def spectral_input(x: torch.Tensor) -> torch.Tensor:
54
55
  return x.to(torch.promote_types(x.dtype, torch.float32))
55
56
 
56
57
 
58
+ def fft_conv1d(
59
+ x: torch.Tensor, weight: torch.Tensor, bias: Optional[torch.Tensor] = None
60
+ ) -> torch.Tensor:
61
+ """``F.conv1d(x, weight, bias, padding="same")`` computed with FFTs.
62
+
63
+ Equal to the direct convolution up to float rounding: the FFT is long
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 on
66
+ CPU (see :func:`prefer_fft_conv`). float16/bfloat16 inputs are computed in
67
+ float32 (:func:`spectral_input`) and cast back.
68
+
69
+ Parameters
70
+ ----------
71
+ x : torch.Tensor
72
+ Input of shape ``(batch, in_channels, n_times)``.
73
+ weight : torch.Tensor
74
+ Kernels of shape ``(out_channels, in_channels, kernel_size)``.
75
+ bias : torch.Tensor | None
76
+ Bias of shape ``(out_channels,)``.
77
+
78
+ Returns
79
+ -------
80
+ torch.Tensor
81
+ Output of shape ``(batch, out_channels, n_times)``, dtype and device of
82
+ ``x``. For an even ``kernel_size`` it is aligned like torch's
83
+ ``padding="same"`` (the extra zero padded on the right).
84
+ """
85
+ n_times, kernel_size = x.shape[-1], weight.shape[-1]
86
+ # >= n_times + kernel_size - 1 (no circular wrap-around), even and
87
+ # 5-smooth: the fast cases of a real FFT
88
+ n_fft = 2 * _next_fast_len((n_times + kernel_size) // 2)
89
+ xs = spectral_input(x)
90
+ # conv1d is a cross-correlation: a convolution with the flipped kernel
91
+ x_f = torch.fft.rfft(xs, n=n_fft).permute(2, 0, 1) # (freq, batch, in)
92
+ w_f = torch.fft.rfft(weight.to(xs).flip(-1), n=n_fft).permute(2, 1, 0)
93
+ # Per frequency (batch, in) @ (in, out) in complex numbers, as one real
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
+ )
101
+ y = torch.fft.irfft(y_f.permute(1, 2, 0), n=n_fft)
102
+ # "same" output t is sample t + kernel_size // 2 of the full convolution
103
+ y = y[..., kernel_size // 2 : kernel_size // 2 + n_times]
104
+ if bias is not None:
105
+ y = y + bias.to(y).unsqueeze(-1)
106
+ return y.to(x)
107
+
108
+
109
+ def prefer_fft_conv(x: torch.Tensor, kernel_size: int) -> bool:
110
+ """Whether :func:`fft_conv1d` is expected to beat a direct convolution.
111
+
112
+ Rule measured for :class:`~braindecode.models.EEGInceptionMI` (48 to 240
113
+ channels, 128-500 Hz, 2 CPU threads, oneDNN on and off): on CPU the FFT
114
+ wins for float16/bfloat16 inputs (no fast half-precision CPU convolution)
115
+ and from ``batch_size * kernel_size >= 600``. GPUs and HPUs (no complex
116
+ dtype) keep the direct convolution.
117
+
118
+ Parameters
119
+ ----------
120
+ x : torch.Tensor
121
+ Input of the convolution, ``(batch, in_channels, n_times)``.
122
+ kernel_size : int
123
+ Kernel length in samples.
124
+ """
125
+ return x.device.type == "cpu" and (
126
+ x.element_size() == 2 or x.shape[0] * kernel_size >= 600
127
+ )
128
+
129
+
130
+ def _next_fast_len(n: int) -> int:
131
+ """Smallest ``2^a 3^b 5^c >= n`` (scipy's ``next_fast_len(n, real=True)``)."""
132
+ n -= 1
133
+ m = 0
134
+ while m != 1:
135
+ n += 1
136
+ m = n
137
+ for p in [2, 3, 5]:
138
+ while m % p == 0:
139
+ m = m // p
140
+ return n
141
+
142
+
57
143
  def drop_path(
58
144
  x, drop_prob: float = 0.0, training: bool = False, scale_by_keep: bool = True
59
145
  ):
@@ -281,18 +367,24 @@ def plv_time(
281
367
  )
282
368
  # Normalize the analytic signal to obtain unit vectors (phasors).
283
369
  unit_phasor = analytic_signal / amplitude.unsqueeze(-1)
370
+ # The real/imaginary slices are strided (step 2): matmul copied each of
371
+ # them for every product, per batch matrix. Copy them once.
372
+ real = unit_phasor[..., 0].contiguous()
373
+ imag = unit_phasor[..., 1].contiguous()
374
+ real_t = real.transpose(-2, -1).contiguous()
375
+ imag_t = imag.transpose(-2, -1).contiguous()
284
376
 
285
377
  # Compute the real part of the outer product between phasors of
286
378
  # different channels.
287
- real_real = torch.matmul(unit_phasor[..., 0], unit_phasor[..., 0].transpose(-2, -1))
379
+ real_real = torch.matmul(real, real_t)
288
380
 
289
381
  # Compute the imaginary part of the outer product between phasors of
290
382
  # different channels.
291
- imag_imag = torch.matmul(unit_phasor[..., 1], unit_phasor[..., 1].transpose(-2, -1))
383
+ imag_imag = torch.matmul(imag, imag_t)
292
384
 
293
385
  # Compute the cross-terms for the real and imaginary parts.
294
- real_imag = torch.matmul(unit_phasor[..., 0], unit_phasor[..., 1].transpose(-2, -1))
295
- imag_real = torch.matmul(unit_phasor[..., 1], unit_phasor[..., 0].transpose(-2, -1))
386
+ real_imag = torch.matmul(real, imag_t)
387
+ imag_real = torch.matmul(imag, real_t)
296
388
 
297
389
  # Combine the real and imaginary parts to form the complex correlation.
298
390
  correlation_real = real_real + imag_imag
@@ -412,7 +504,14 @@ def dwt_max_level(n_times: int, filter_len: int) -> int:
412
504
  """
413
505
  if n_times < filter_len:
414
506
  return 0
415
- return max(0, int(math.floor(math.log2(n_times / (filter_len - 1)))))
507
+ # floor(log2(n_times / (filter_len - 1))) in integers (TorchScript has no
508
+ # math.log2): the largest level with (filter_len - 1) * 2**level <= n_times.
509
+ ratio = n_times // (filter_len - 1)
510
+ level = 0
511
+ while ratio >= 2:
512
+ ratio = ratio // 2
513
+ level += 1
514
+ return level
416
515
 
417
516
 
418
517
  def wavelet_decomposition(
@@ -456,8 +555,9 @@ def wavelet_decomposition(
456
555
  )
457
556
  approx, detail = F.conv1d(padded, weight, stride=2).unbind(dim=1)
458
557
  details.append(detail)
459
- out = torch.cat([approx, *reversed(details)], dim=-1)
460
- return out.reshape(*leading, -1)
558
+ details.reverse() # [cD_n, ..., cD_1]
559
+ out = torch.cat([approx] + details, dim=-1)
560
+ return out.reshape(list(leading) + [-1])
461
561
 
462
562
 
463
563
  def sinusoidal_positional_encoding(
@@ -1,12 +1,13 @@
1
+ from typing import Dict, Optional, Tuple, Union
1
2
  from warnings import warn
2
3
 
3
4
  import torch
4
5
  import torch.nn as nn
5
- from linear_attention_transformer import LinearAttentionTransformer
6
6
 
7
7
  from braindecode.functional import sinusoidal_positional_encoding, spectral_input
8
8
  from braindecode.models.base import EEGModuleMixin
9
9
  from braindecode.models.util import warn_if_sfreq_differs
10
+ from braindecode.modules.linear_attention import LinearAttentionTransformer
10
11
 
11
12
  # -----------------------------------------------------------------------------
12
13
  # Canonical BIOT channel order: the 18-channel TCP bipolar montage used by
@@ -230,7 +231,13 @@ class BIOT(EEGModuleMixin, nn.Module):
230
231
  activation=self._head_activation,
231
232
  )
232
233
 
233
- def forward(self, x, return_features=False):
234
+ def forward(
235
+ self, x: torch.Tensor, return_features: bool = False
236
+ ) -> Union[
237
+ torch.Tensor,
238
+ Tuple[torch.Tensor, torch.Tensor],
239
+ Dict[str, Optional[torch.Tensor]],
240
+ ]:
234
241
  """
235
242
  Pass the input through the BIOT encoder, and then through the
236
243
  classification head.
@@ -255,7 +262,11 @@ class BIOT(EEGModuleMixin, nn.Module):
255
262
  emb = self.encoder(x)
256
263
 
257
264
  if return_features:
258
- return {"features": emb, "cls_token": None}
265
+ out: Dict[str, Optional[torch.Tensor]] = {
266
+ "features": emb,
267
+ "cls_token": None,
268
+ }
269
+ return out
259
270
 
260
271
  x = self.final_layer(emb)
261
272
 
@@ -454,9 +465,7 @@ class _BIOTEncoder(nn.Module):
454
465
  dim=emb_size,
455
466
  heads=num_heads,
456
467
  depth=n_layers,
457
- max_seq_len=max_seq_len,
458
468
  attn_layer_dropout=attn_layer_dropout,
459
- attn_dropout=attn_dropout,
460
469
  )
461
470
  self.positional_encoding = _PositionalEncoding(emb_size, drop_prob=drop_prob)
462
471
 
@@ -497,7 +506,7 @@ class _BIOTEncoder(nn.Module):
497
506
  )
498
507
  return torch.abs(spectral).to(sample)
499
508
 
500
- def forward(self, x, n_channel_offset=0, perturb=False):
509
+ def forward(self, x, n_channel_offset: int = 0, perturb: bool = False):
501
510
  """
502
511
  Forward pass of the BIOT encoder.
503
512
 
@@ -569,7 +578,7 @@ class _BIOTEncoder(nn.Module):
569
578
  # of time steps.
570
579
  if perturb:
571
580
  ts = channel_emb.shape[1]
572
- ts_new = torch.randint(low=ts // 2, high=ts, size=(1,)).item()
581
+ ts_new = int(torch.randint(low=ts // 2, high=ts, size=(1,)).item())
573
582
  selected_ts = torch.randperm(ts)[:ts_new]
574
583
  channel_emb = channel_emb[:, selected_ts]
575
584
  emb_seq.append(channel_emb)
@@ -7,12 +7,13 @@
7
7
  # derives from Meta's EnCodec (MIT).
8
8
  from __future__ import annotations
9
9
 
10
+ from typing import Dict, Optional, Union
11
+
10
12
  import mne
11
13
  import numpy as np
12
14
  import torch
13
15
  import torch.nn as nn
14
16
  import torch.nn.functional as F
15
- from einops import rearrange
16
17
  from mne.io.constants import FIFF
17
18
  from torch.nn import RMSNorm
18
19
  from torch.nn.utils.parametrizations import weight_norm
@@ -276,8 +277,7 @@ class BrainTokenizer(EEGModuleMixin, nn.Module, license="mit"):
276
277
  feat, indices, _, _ = self._encode_quantize(x, overlap_ratio)
277
278
  finally:
278
279
  self.train(was_training)
279
- flat = "batch chans nwin tok dim -> batch chans (nwin tok) dim"
280
- return rearrange(feat, flat), rearrange(indices, flat)
280
+ return feat.flatten(2, 3), indices.flatten(2, 3)
281
281
 
282
282
 
283
283
  class BrainOmni(EEGModuleMixin, nn.Module, license="mit"):
@@ -488,18 +488,33 @@ class BrainOmni(EEGModuleMixin, nn.Module, license="mit"):
488
488
 
489
489
  def encode(self, x: torch.Tensor) -> torch.Tensor:
490
490
  """L2-normalized ``(batch, n_neuro, n_tokens, lm_dim)`` embedding."""
491
- feat, _ = self.tokenizer.tokenize(x, overlap_ratio=self.overlap_ratio)
491
+ if torch.jit.is_scripting():
492
+ # TorchScript cannot switch modes, so tokenize() is not scriptable.
493
+ if self.tokenizer.training:
494
+ raise RuntimeError("Scripted BrainOmni needs tokenizer.eval().")
495
+ with torch.no_grad():
496
+ feat = self.tokenizer._encode_quantize(x, self.overlap_ratio)[0]
497
+ feat = feat.flatten(2, 3)
498
+ else:
499
+ feat, _ = self.tokenizer.tokenize(x, overlap_ratio=self.overlap_ratio)
492
500
  neuro = self.tokenizer.encoder.neuros.detach().to(feat.dtype)
493
501
  h = self.projection(feat + neuro.view(1, feat.shape[1], 1, -1))
494
- for block in self.blocks[:-1]:
495
- h = block(h)
502
+ for i, block in enumerate(self.blocks): # the last block is unused, as released
503
+ if i < len(self.blocks) - 1:
504
+ h = block(h)
496
505
  return F.normalize(h, p=2.0, dim=-1, eps=1e-6)
497
506
 
498
- def forward(self, x: torch.Tensor, return_features: bool = False):
507
+ def forward(
508
+ self, x: torch.Tensor, return_features: bool = False
509
+ ) -> Union[torch.Tensor, Dict[str, Optional[torch.Tensor]]]:
499
510
  """Classify ``x`` or return the pooled features."""
500
511
  feat = self.encode(x).mean(dim=2).flatten(1) # (batch, n_neuro * lm_dim)
501
512
  if return_features:
502
- return {"features": feat, "cls_token": None} # nosec B105
513
+ out: Dict[str, Optional[torch.Tensor]] = {
514
+ "features": feat,
515
+ "cls_token": None, # nosec B105
516
+ }
517
+ return out
503
518
  return self.final_layer(feat)
504
519
 
505
520
 
@@ -583,11 +598,11 @@ def _geometry_from_chs_info(chs_info):
583
598
  return pos, sensor_type
584
599
 
585
600
 
586
- def _attend(q, k, v, n_head: int, dropout_p: float, rope=None) -> torch.Tensor:
601
+ def _attend(q, k, v, n_head: int, dropout_p: float) -> torch.Tensor:
587
602
  """SDPA over ``(batch, seq, n_head * head_dim)`` inputs."""
588
- q, k, v = (t.unflatten(-1, (n_head, -1)) for t in (q, k, v))
589
- if rope is not None:
590
- q, k = rope(q, k)
603
+ q = q.unflatten(-1, (n_head, -1))
604
+ k = k.unflatten(-1, (n_head, -1))
605
+ v = v.unflatten(-1, (n_head, -1))
591
606
  out = F.scaled_dot_product_attention(
592
607
  q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2), dropout_p=dropout_p
593
608
  )
@@ -609,12 +624,13 @@ class _SpatialTemporalBlock(nn.Module):
609
624
  self.ff = FeedForwardBlock(n_dim, 4, 0.0, _SELU, output_drop_p=dropout)
610
625
 
611
626
  def forward(self, x: torch.Tensor) -> torch.Tensor:
612
- batch, _, _, dim = x.shape
627
+ batch, chans, times, dim = x.shape
613
628
  h = self.pre_attn_norm(x)
614
- xs = rearrange(h[..., dim // 2 :], "b c t d -> (b t) c d")
615
- xt = rearrange(h[..., : dim // 2], "b c t d -> (b c) t d")
616
- xs = rearrange(self.spatial_attn(xs), "(b t) c d -> b c t d", b=batch)
617
- xt = rearrange(self.time_attn(xt), "(b c) t d -> b c t d", b=batch)
629
+ # (b, c, t, d) -> (b * t, c, d) and (b * c, t, d), and back
630
+ xs = h[..., dim // 2 :].permute(0, 2, 1, 3).reshape(batch * times, chans, -1)
631
+ xt = h[..., : dim // 2].reshape(batch * chans, times, -1)
632
+ xs = self.spatial_attn(xs).reshape(batch, times, chans, -1).permute(0, 2, 1, 3)
633
+ xt = self.time_attn(xt).reshape(batch, chans, times, -1)
618
634
  # Spatial half first: the halves swap, as released.
619
635
  x = x + torch.cat([xs, xt], dim=-1)
620
636
  return x + self.ff(self.pre_ff_norm(x))
@@ -629,6 +645,10 @@ class _RotaryPositionalEmbedding(nn.Module):
629
645
  float32 under a dtype cast, ``freqs`` follows it.
630
646
  """
631
647
 
648
+ # TorchScript types the ``rebuilt`` buffer from this; a postponed string
649
+ # annotation would not resolve.
650
+ __annotations__ = {"rebuilt": Optional[torch.Tensor]}
651
+
632
652
  def __init__(self, n_dim, base=10000):
633
653
  super().__init__()
634
654
  self.n_dim = n_dim
@@ -658,13 +678,15 @@ class _RotaryPositionalEmbedding(nn.Module):
658
678
  def forward(self, q, k):
659
679
  """Rotate ``q`` and ``k`` of shape ``(batch, seq, n_heads, head_dim)``."""
660
680
  _, seq, heads, _ = q.shape
661
- rotate = self.rotate if self.rebuilt is None else self.rebuilt
681
+ rebuilt = self.rebuilt
682
+ rotate = self.rotate if rebuilt is None else rebuilt
662
683
  if seq > rotate.shape[0]:
663
- self.rebuilt = rotate = self._polar(seq)
684
+ rotate = self._polar(seq)
685
+ self.rebuilt = rotate
664
686
  # In at least float32 (the cache's dtype), float64 for float64 inputs.
665
687
  work = torch.promote_types(q.dtype, torch.float32)
666
688
  rotate = rotate.to(work)[:seq].repeat_interleave(2, dim=1)
667
- rotate = rearrange(rotate, "s (h d) two -> s h d two", h=heads)
689
+ rotate = rotate.unflatten(1, (heads, -1)) # (seq, heads, head_dim, 2)
668
690
  cos, sin = rotate[..., 0], rotate[..., 1]
669
691
  q_float, k_float = q.to(work), k.to(work)
670
692
  q_out = q_float * cos + rotate_pairs(q_float) * sin
@@ -687,7 +709,12 @@ class _MultiHeadAttentionRoPE(nn.Module):
687
709
  def forward(self, x: torch.Tensor) -> torch.Tensor:
688
710
  q, k, v = torch.split(self.qkv(x), self.n_dim, dim=-1)
689
711
  dropout_p = self.dropout if self.training else 0.0
690
- out = _attend(q, k, v, self.n_head, dropout_p, self.rope_embedding_layer)
712
+ if self.rope_embedding_layer is not None: # on (batch, seq, heads, head_dim)
713
+ q, k = self.rope_embedding_layer(
714
+ q.unflatten(-1, (self.n_head, -1)), k.unflatten(-1, (self.n_head, -1))
715
+ )
716
+ q, k = q.flatten(2), k.flatten(2)
717
+ out = _attend(q, k, v, self.n_head, dropout_p)
691
718
  return self.proj(out)
692
719
 
693
720
 
@@ -765,19 +792,22 @@ class _TokenizerEncoder(nn.Module):
765
792
  self.k_proj = nn.Linear(n_dim, n_dim)
766
793
 
767
794
  def forward(self, x: torch.Tensor, sensor_embedding: torch.Tensor):
768
- batch, chans, nwin, _ = x.shape
769
- x = self.seanet_encoder(rearrange(x, "b c w l -> (b c w) 1 l"))
770
- x = rearrange(x, "(b c w) d t -> b c (w t) d", b=batch, c=chans, w=nwin)
771
- tokens = x.shape[2]
772
- sensor_embedding = rearrange(
773
- sensor_embedding.unsqueeze(2).repeat(1, 1, tokens, 1),
774
- "b c t d -> (b t) c d",
775
- )
776
- x = rearrange(x, "b c t d -> (b t) c d")
795
+ batch, chans, nwin, length = x.shape
796
+ x = self.seanet_encoder(x.reshape(batch * chans * nwin, 1, length))
797
+ # (b c w) d t -> b c (w t) d
798
+ x = x.reshape(batch, chans, nwin, x.shape[1], -1).permute(0, 1, 2, 4, 3)
799
+ x = x.reshape(batch, chans, -1, x.shape[-1])
800
+ tokens, dim = x.shape[2], x.shape[3]
801
+ # b c t d -> (b t) c d
802
+ sensor_embedding = sensor_embedding.unsqueeze(2).repeat(1, 1, tokens, 1)
803
+ sensor_embedding = sensor_embedding.permute(0, 2, 1, 3).reshape(-1, chans, dim)
804
+ x = x.permute(0, 2, 1, 3).reshape(-1, chans, dim)
777
805
  neuros = self.neuros.type_as(x).unsqueeze(0).repeat(x.shape[0], 1, 1)
778
806
  x = self.backwardsolution(neuros, self.k_proj(x + sensor_embedding), x)
779
- x = rearrange(x, "(b w t) c d -> b c (w t) d", b=batch, w=nwin)
780
- return rearrange(x, "b c (w t) d -> b c w t d", w=nwin)
807
+ # (b w t) c d -> b c (w t) d -> b c w t d
808
+ x = x.reshape(batch, nwin, -1, x.shape[1], dim).permute(0, 3, 1, 2, 4)
809
+ x = x.reshape(batch, x.shape[1], -1, dim)
810
+ return x.reshape(batch, x.shape[1], nwin, -1, dim)
781
811
 
782
812
 
783
813
  class _TokenizerDecoder(nn.Module):
@@ -800,16 +830,21 @@ class _TokenizerDecoder(nn.Module):
800
830
  )
801
831
 
802
832
  def forward(self, x: torch.Tensor, sensor_embedding: torch.Tensor):
803
- batch, _, nwin, tok, dim = x.shape
804
- x = rearrange(x, "b c w t d -> (b w t) c d")
805
- sensor_embedding = rearrange(
806
- sensor_embedding.view(batch, -1, 1, 1, dim).repeat(1, 1, nwin, tok, 1),
807
- "b c w t d -> (b w t) c d",
833
+ batch, sources, nwin, tok, dim = x.shape
834
+ # b c w t d -> (b w t) c d
835
+ x = x.permute(0, 2, 3, 1, 4).reshape(-1, sources, dim)
836
+ sensor_embedding = sensor_embedding.view(batch, -1, 1, 1, dim)
837
+ chans = sensor_embedding.shape[1]
838
+ sensor_embedding = sensor_embedding.repeat(1, 1, nwin, tok, 1)
839
+ sensor_embedding = sensor_embedding.permute(0, 2, 3, 1, 4).reshape(
840
+ -1, chans, dim
808
841
  )
809
842
  x = self.forwardsolution(sensor_embedding, x)
810
- x = rearrange(x, "(b w t) c d -> (b c w) d t", b=batch, w=nwin, t=tok)
811
- x = self.seanet_decoder(x)
812
- return rearrange(x, "(b c w) 1 l -> b c w l", b=batch, w=nwin)
843
+ # (b w t) c d -> (b c w) d t
844
+ x = x.reshape(batch, nwin, tok, chans, dim).permute(0, 3, 1, 4, 2)
845
+ x = self.seanet_decoder(x.reshape(-1, dim, tok))
846
+ # (b c w) 1 l -> b c w l
847
+ return x.reshape(batch, chans, nwin, x.shape[-1])
813
848
 
814
849
 
815
850
  class _SEANetConv1d(nn.Module):
@@ -316,7 +316,7 @@ class DANCE(EEGModuleMixin, nn.Module, license="mit"):
316
316
  def _encode(self, x: torch.Tensor) -> torch.Tensor:
317
317
  if x.ndim != 3 or x.shape[-2] != self.n_chans:
318
318
  raise ValueError(
319
- f"expected (batch, {self.n_chans}, T) input; got {tuple(x.shape)}."
319
+ f"expected (batch, {self.n_chans}, T) input; got {list(x.shape)}."
320
320
  )
321
321
  if x.shape[-1] < self._min_n_times:
322
322
  raise ValueError(