braindecode 1.8.1.dev173644701__tar.gz → 1.8.1.dev173738593__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. {braindecode-1.8.1.dev173644701/braindecode.egg-info → braindecode-1.8.1.dev173738593}/PKG-INFO +2 -1
  2. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/functional/__init__.py +13 -0
  3. braindecode-1.8.1.dev173738593/braindecode/functional/attention.py +152 -0
  4. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/functional/functions.py +106 -1
  5. braindecode-1.8.1.dev173738593/braindecode/functional/patches.py +105 -0
  6. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/atcnet.py +4 -14
  7. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/attn_sleep.py +9 -13
  8. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/axon.py +5 -3
  9. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/barista.py +17 -18
  10. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/biot.py +6 -56
  11. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/brainbert.py +9 -8
  12. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/brainmodule.py +1 -1
  13. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/brainomni.py +4 -5
  14. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/brant.py +3 -3
  15. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/codebrain.py +1 -1
  16. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/csbrain.py +3 -3
  17. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/ctnet.py +15 -55
  18. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/diver1.py +11 -8
  19. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/duin.py +7 -3
  20. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/eegdino.py +16 -66
  21. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/eegpt.py +19 -338
  22. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/epint.py +11 -6
  23. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/ifnet.py +20 -24
  24. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/labram.py +1 -1
  25. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/luna.py +35 -91
  26. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/medformer.py +11 -20
  27. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/mscformer.py +16 -60
  28. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/neurorvq.py +39 -61
  29. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/neurorvq_tokenizer.py +5 -5
  30. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/patchedtransformer.py +2 -3
  31. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/popt.py +2 -8
  32. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/reve.py +10 -10
  33. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/signal_jepa.py +12 -13
  34. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/sleepfm.py +3 -3
  35. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/tcformer.py +22 -24
  36. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/tmsanet.py +9 -9
  37. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/util.py +19 -3
  38. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/zuna.py +2 -2
  39. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/__init__.py +10 -0
  40. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/attention.py +102 -84
  41. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/blocks.py +42 -61
  42. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/dance_modules.py +5 -3
  43. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/layers.py +134 -2
  44. braindecode-1.8.1.dev173738593/braindecode/version.py +1 -0
  45. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593/braindecode.egg-info}/PKG-INFO +2 -1
  46. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode.egg-info/SOURCES.txt +2 -0
  47. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode.egg-info/requires.txt +1 -0
  48. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/api.rst +13 -0
  49. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/whats_new.rst +14 -0
  50. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/pyproject.toml +6 -0
  51. braindecode-1.8.1.dev173644701/braindecode/version.py +0 -1
  52. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/LICENSE.txt +0 -0
  53. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/MANIFEST.in +0 -0
  54. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/NOTICE.txt +0 -0
  55. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/README.rst +0 -0
  56. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/__init__.py +0 -0
  57. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/augmentation/__init__.py +0 -0
  58. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/augmentation/base.py +0 -0
  59. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/augmentation/functional.py +0 -0
  60. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/augmentation/transforms.py +0 -0
  61. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/classifier.py +0 -0
  62. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/__init__.py +0 -0
  63. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/_notebook_viewer.py +0 -0
  64. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/base.py +0 -0
  65. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/bbci.py +0 -0
  66. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/bcicomp.py +0 -0
  67. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/bids/__init__.py +0 -0
  68. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/bids/datasets.py +0 -0
  69. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/bids/hub.py +0 -0
  70. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/bids/hub_format.py +0 -0
  71. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/bids/hub_io.py +0 -0
  72. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/bids/hub_validation.py +0 -0
  73. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/bids/iterable.py +0 -0
  74. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/chb_mit.py +0 -0
  75. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/collate.py +0 -0
  76. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/mne.py +0 -0
  77. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/moabb.py +0 -0
  78. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/nmt.py +0 -0
  79. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/registry.py +0 -0
  80. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/siena.py +0 -0
  81. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  82. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/sleep_physionet.py +0 -0
  83. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/tuh.py +0 -0
  84. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/utils.py +0 -0
  85. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datasets/xy.py +0 -0
  86. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datautil/__init__.py +0 -0
  87. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datautil/channel_utils.py +0 -0
  88. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datautil/hub_formats.py +0 -0
  89. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datautil/serialization.py +0 -0
  90. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/datautil/util.py +0 -0
  91. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/eegneuralnet.py +0 -0
  92. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/functional/_real_dft.py +0 -0
  93. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/functional/initialization.py +0 -0
  94. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/__init__.py +0 -0
  95. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/attentionbasenet.py +0 -0
  96. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/base.py +0 -0
  97. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/bendr.py +0 -0
  98. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/cbramod.py +0 -0
  99. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/config.py +0 -0
  100. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/contrawr.py +0 -0
  101. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/dance.py +0 -0
  102. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/deep4.py +0 -0
  103. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/deepsleepnet.py +0 -0
  104. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/dgcnn.py +0 -0
  105. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/eeg_clip.py +0 -0
  106. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/eegconformer.py +0 -0
  107. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/eeginception_erp.py +0 -0
  108. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/eeginception_mi.py +0 -0
  109. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/eegitnet.py +0 -0
  110. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/eegminer.py +0 -0
  111. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/eegnet.py +0 -0
  112. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/eegnex.py +0 -0
  113. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/eegsimpleconv.py +0 -0
  114. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/eegsym.py +0 -0
  115. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/eegtcnet.py +0 -0
  116. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/emg2qwerty.py +0 -0
  117. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/fbcnet.py +0 -0
  118. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/fblightconvnet.py +0 -0
  119. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/fbmsnet.py +0 -0
  120. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/gcnsnet.py +0 -0
  121. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/guetschel2026.py +0 -0
  122. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/hybrid.py +0 -0
  123. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/mapa.py +0 -0
  124. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/meta_neuromotor.py +0 -0
  125. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/mirepnet.py +0 -0
  126. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/msvtnet.py +0 -0
  127. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/mvpformer.py +0 -0
  128. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/neuropose.py +0 -0
  129. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/sccnet.py +0 -0
  130. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/seizure_transformer.py +0 -0
  131. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/sensingdynamics.py +0 -0
  132. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/shallow_fbcsp.py +0 -0
  133. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/sinc_shallow.py +0 -0
  134. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
  135. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  136. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/sparcnet.py +0 -0
  137. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/sstdpn.py +0 -0
  138. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/steegformer.py +0 -0
  139. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/summary.csv +0 -0
  140. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/syncnet.py +0 -0
  141. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/tcn.py +0 -0
  142. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/tfm_tokenizer.py +0 -0
  143. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/tidnet.py +0 -0
  144. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/tsinception.py +0 -0
  145. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/usleep.py +0 -0
  146. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/models/vemg2pose.py +0 -0
  147. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/activation.py +0 -0
  148. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/channels.py +0 -0
  149. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/convolution.py +0 -0
  150. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/filter.py +0 -0
  151. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/linear.py +0 -0
  152. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/linear_attention.py +0 -0
  153. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/parametrization.py +0 -0
  154. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/quantization.py +0 -0
  155. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/stats.py +0 -0
  156. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/util.py +0 -0
  157. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/modules/wrapper.py +0 -0
  158. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/preprocessing/__init__.py +0 -0
  159. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
  160. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/preprocessing/mne_preprocess.py +0 -0
  161. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/preprocessing/preprocess.py +0 -0
  162. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/preprocessing/util.py +0 -0
  163. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/preprocessing/windowers.py +0 -0
  164. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/regressor.py +0 -0
  165. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/samplers/__init__.py +0 -0
  166. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/samplers/base.py +0 -0
  167. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/samplers/ssl.py +0 -0
  168. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/training/__init__.py +0 -0
  169. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/training/callbacks.py +0 -0
  170. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/training/losses.py +0 -0
  171. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/training/scoring.py +0 -0
  172. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/util.py +0 -0
  173. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/visualization/__init__.py +0 -0
  174. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/visualization/activations.py +0 -0
  175. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/visualization/attribution.py +0 -0
  176. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/visualization/confusion_matrices.py +0 -0
  177. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/visualization/frequency.py +0 -0
  178. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/visualization/metrics.py +0 -0
  179. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/visualization/sanity.py +0 -0
  180. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode/visualization/topology.py +0 -0
  181. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode.egg-info/dependency_links.txt +0 -0
  182. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/braindecode.egg-info/top_level.txt +0 -0
  183. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/Makefile +0 -0
  184. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/_templates/autosummary/class.rst +0 -0
  185. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  186. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/_templates/autosummary/function.rst +0 -0
  187. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  188. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/agent_docs.rst +0 -0
  189. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/cite.rst +0 -0
  190. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/conf.py +0 -0
  191. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/help.rst +0 -0
  192. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/index.rst +0 -0
  193. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/install/install.rst +0 -0
  194. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/install/install_pip.rst +0 -0
  195. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/install/install_source.rst +0 -0
  196. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/models/categorization/attention.rst +0 -0
  197. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/models/categorization/channel.rst +0 -0
  198. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/models/categorization/convolution.rst +0 -0
  199. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/models/categorization/filterbank.rst +0 -0
  200. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/models/categorization/gnn.rst +0 -0
  201. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/models/categorization/interpretable.rst +0 -0
  202. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/models/categorization/lbm.rst +0 -0
  203. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/models/categorization/recurrent.rst +0 -0
  204. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/models/categorization/spd.rst +0 -0
  205. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/models/models.rst +0 -0
  206. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/models/models_categorization.rst +0 -0
  207. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/models/models_table.rst +0 -0
  208. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/models/models_visualization.rst +0 -0
  209. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/sg_execution_times.rst +0 -0
  210. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/docs/user_guide/channel_strategies.rst +0 -0
  211. {braindecode-1.8.1.dev173644701 → braindecode-1.8.1.dev173738593}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.8.1.dev173644701
3
+ Version: 1.8.1.dev173738593
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>
@@ -50,6 +50,7 @@ Provides-Extra: tests
50
50
  Requires-Dist: pytest<9.1; extra == "tests"
51
51
  Requires-Dist: pytest-cov; extra == "tests"
52
52
  Requires-Dist: pytest-xdist>=3.8.0; extra == "tests"
53
+ Requires-Dist: pytest-timeout; extra == "tests"
53
54
  Requires-Dist: codecov; extra == "tests"
54
55
  Requires-Dist: pytest_cases; extra == "tests"
55
56
  Requires-Dist: mypy; extra == "tests"
@@ -1,5 +1,7 @@
1
+ from .attention import scaled_dot_product_attention
1
2
  from .functions import (
2
3
  _get_gaussian_kernel1d,
4
+ apply_rotary,
3
5
  daubechies_filters,
4
6
  drop_path,
5
7
  dwt_max_level,
@@ -10,6 +12,9 @@ from .functions import (
10
12
  pairwise_iou_1d,
11
13
  plv_time,
12
14
  prefer_fft_conv,
15
+ rotary_angles,
16
+ rotary_frequencies,
17
+ rotate_half,
13
18
  rotate_pairs,
14
19
  safe_log,
15
20
  sinusoidal_positional_encoding,
@@ -22,9 +27,11 @@ from .initialization import (
22
27
  init_weights_,
23
28
  rescale_parameter,
24
29
  )
30
+ from .patches import pad_or_crop_to_patches, patch_count
25
31
 
26
32
  __all__ = [
27
33
  "_get_gaussian_kernel1d",
34
+ "apply_rotary",
28
35
  "daubechies_filters",
29
36
  "drop_path",
30
37
  "dwt_max_level",
@@ -32,11 +39,17 @@ __all__ = [
32
39
  "hilbert_freq",
33
40
  "identity",
34
41
  "iou_1d",
42
+ "pad_or_crop_to_patches",
35
43
  "pairwise_iou_1d",
44
+ "patch_count",
36
45
  "plv_time",
37
46
  "prefer_fft_conv",
47
+ "rotary_angles",
48
+ "rotary_frequencies",
49
+ "rotate_half",
38
50
  "rotate_pairs",
39
51
  "safe_log",
52
+ "scaled_dot_product_attention",
40
53
  "sinusoidal_positional_encoding",
41
54
  "spectral_input",
42
55
  "square",
@@ -0,0 +1,152 @@
1
+ """Scaled dot-product attention with the device-specific paths in one place."""
2
+
3
+ # Authors: Bruno Aristimunha <b.aristimunha@gmail.com>
4
+ #
5
+ # License: BSD (3-clause)
6
+
7
+ import math
8
+ from typing import Optional
9
+
10
+ import torch
11
+ import torch.nn.functional as F
12
+ from torch import Tensor
13
+
14
+
15
+ @torch.jit.unused
16
+ def _hpu_eager_fused_sdpa(
17
+ query: Tensor,
18
+ key: Tensor,
19
+ value: Tensor,
20
+ scale: Optional[float] = None,
21
+ fused_in_lazy: bool = False,
22
+ ) -> Optional[Tensor]:
23
+ # Lazy mode: None, the graph compiler already fuses torch's SDPA there
24
+ # (unless the caller measured the fused kernel faster for its shapes).
25
+ from habana_frameworks.torch.utils.internal import is_lazy
26
+
27
+ if is_lazy() and not fused_in_lazy:
28
+ return None
29
+ from habana_frameworks.torch.hpex.kernels import FusedSDPA
30
+
31
+ # Strided q/k/v views (heads split off a projection) give wrong outputs and
32
+ # gradients at some shapes; contiguous copies give the right result.
33
+ query, key, value = query.contiguous(), key.contiguous(), value.contiguous()
34
+ return FusedSDPA.apply(query, key, value, None, 0.0, False, scale, "None", False)
35
+
36
+
37
+ @torch.jit.unused
38
+ def _hpu_lazy() -> bool:
39
+ from habana_frameworks.torch.utils.internal import is_lazy
40
+
41
+ return is_lazy()
42
+
43
+
44
+ def _sdpa_math_dropout(
45
+ query: Tensor,
46
+ key: Tensor,
47
+ value: Tensor,
48
+ dropout_p: float,
49
+ scale: Optional[float] = None,
50
+ ) -> Tensor:
51
+ # torch's math path for SDPA with dropout, op for op, without the pass of
52
+ # ``_safe_softmax`` that zeroes fully masked rows (none without a mask):
53
+ # same values, same dropout draws.
54
+ if scale is None:
55
+ scale = 1.0 / math.sqrt(query.size(-1))
56
+ half = math.sqrt(scale)
57
+ attn = torch.matmul(query * half, key.transpose(-2, -1) * half)
58
+ attn = F.dropout(attn.softmax(-1), dropout_p, True)
59
+ return torch.matmul(attn, value)
60
+
61
+
62
+ def scaled_dot_product_attention(
63
+ query: Tensor,
64
+ key: Tensor,
65
+ value: Tensor,
66
+ attn_mask: Optional[Tensor] = None,
67
+ dropout_p: float = 0.0,
68
+ scale: Optional[float] = None,
69
+ fused_in_lazy: bool = False,
70
+ exact: bool = False,
71
+ ) -> Tensor:
72
+ """``F.scaled_dot_product_attention``; Gaudi's fused kernel on HPU.
73
+
74
+ Parameters
75
+ ----------
76
+ query, key, value : torch.Tensor
77
+ Shape ``(..., seq, head_dim)``; ``key``/``value`` may have another
78
+ sequence length.
79
+ attn_mask : torch.Tensor, optional
80
+ Boolean (``True`` takes part) or additive mask, as in torch.
81
+ dropout_p : float, default=0.0
82
+ Dropout on the attention weights; pass ``0.0`` in eval mode.
83
+ scale : float, optional
84
+ Score scale; ``None`` is ``1 / sqrt(head_dim)``.
85
+ fused_in_lazy : bool, default=False
86
+ Use Gaudi's fused kernel in HPU lazy mode too.
87
+ exact : bool, default=False
88
+ Run the textbook op order instead of torch's kernels:
89
+ ``softmax((q @ k^T) / sqrt(d)) @ v``, or ``softmax((q @ k^T) * scale) @ v``
90
+ when ``scale`` is given, with dropout on the weights. Bit-identical to
91
+ a hand-written attention; torch's kernels round differently (its math
92
+ path scales ``q`` and ``k`` by ``sqrt(scale)`` each before the matmul,
93
+ its fused CPU kernel runs a blocked softmax), about 1e-6 apart.
94
+
95
+ Returns
96
+ -------
97
+ torch.Tensor
98
+ Shape ``(..., seq, head_dim)``.
99
+
100
+ In HPU eager mode, torch's SDPA runs op by op (the full
101
+ ``(batch, heads, seq, seq)`` scores in device memory), 2-3.5x slower than
102
+ the bridge's fused kernel on long sequences. The fused kernel is used
103
+ without a mask or dropout (its dropout would draw other masks). In lazy
104
+ mode only with ``fused_in_lazy=True``: the graph compiler fuses torch's
105
+ SDPA too, faster on long sequences, slower on short ones.
106
+ """
107
+ if exact:
108
+ scores = torch.matmul(query, key.transpose(-2, -1))
109
+ if scale is None:
110
+ scores = scores / math.sqrt(query.size(-1))
111
+ else:
112
+ scores = scores * scale
113
+ if attn_mask is not None:
114
+ if attn_mask.dtype == torch.bool:
115
+ scores = scores.masked_fill(~attn_mask, float("-inf"))
116
+ else:
117
+ scores = scores + attn_mask
118
+ weights = scores.softmax(dim=-1)
119
+ if dropout_p > 0.0:
120
+ weights = F.dropout(weights, dropout_p, True)
121
+ return torch.matmul(weights, value)
122
+ if (
123
+ not torch.jit.is_scripting()
124
+ and query.device.type == "hpu"
125
+ and attn_mask is None
126
+ and dropout_p == 0.0
127
+ and (query.dtype == torch.float32 or query.dtype == torch.bfloat16)
128
+ ):
129
+ out = _hpu_eager_fused_sdpa(
130
+ query, key, value, scale=scale, fused_in_lazy=fused_in_lazy
131
+ )
132
+ if out is not None:
133
+ return out
134
+ if (
135
+ not torch.jit.is_scripting()
136
+ and dropout_p > 0.0
137
+ and attn_mask is None
138
+ and (query.dtype == torch.float32 or query.dtype == torch.float64)
139
+ and (
140
+ query.device.type == "cpu"
141
+ or (query.device.type == "hpu" and not _hpu_lazy())
142
+ )
143
+ ):
144
+ # CPU and HPU eager run SDPA with dropout through the math path.
145
+ return _sdpa_math_dropout(query, key, value, dropout_p, scale)
146
+ if scale is None: # torch 2.0's signature has no ``scale``
147
+ return F.scaled_dot_product_attention(
148
+ query, key, value, attn_mask=attn_mask, dropout_p=dropout_p
149
+ )
150
+ return F.scaled_dot_product_attention(
151
+ query, key, value, attn_mask=attn_mask, dropout_p=dropout_p, scale=scale
152
+ )
@@ -588,6 +588,7 @@ def sinusoidal_positional_encoding(
588
588
  dim: int,
589
589
  device: torch.device | None = None,
590
590
  dtype: torch.dtype = torch.float32,
591
+ base: float = 10000.0,
591
592
  ) -> torch.Tensor:
592
593
  r"""Fixed sine/cosine positional-encoding table of shape ``(n_positions, dim)``.
593
594
 
@@ -609,6 +610,9 @@ def sinusoidal_positional_encoding(
609
610
  Device of the table (default: CPU), for tables built inside ``forward``.
610
611
  dtype : torch.dtype
611
612
  Floating dtype the table is computed in.
613
+ base : float, default=10000.0
614
+ Longest wavelength, the ``10000`` of Vaswani et al.; SignalJEPA uses the
615
+ largest number of time samples it encodes.
612
616
 
613
617
  Returns
614
618
  -------
@@ -620,7 +624,7 @@ def sinusoidal_positional_encoding(
620
624
  position = torch.arange(n_positions, device=device).unsqueeze(1).to(dtype)
621
625
  div_term = torch.exp(
622
626
  torch.arange(0, dim_even, 2, device=device).to(dtype)
623
- * (-math.log(10000.0) / dim_even)
627
+ * (-math.log(base) / dim_even)
624
628
  )
625
629
  pe = torch.zeros(n_positions, dim_even, device=device, dtype=dtype)
626
630
  pe[:, 0::2] = torch.sin(position * div_term)
@@ -646,3 +650,104 @@ def rotate_pairs(x: torch.Tensor) -> torch.Tensor:
646
650
  """
647
651
  pairs = x.unflatten(-1, (-1, 2))
648
652
  return torch.stack((-pairs[..., 1], pairs[..., 0]), dim=-1).flatten(-2)
653
+
654
+
655
+ def rotate_half(x: torch.Tensor) -> torch.Tensor:
656
+ """Rotate the two feature halves from ``(a, b)`` to ``(-b, a)``.
657
+
658
+ The half-split layout of GPT-NeoX / LLaMA rotary embeddings; see
659
+ :func:`rotate_pairs` for the interleaved layout.
660
+
661
+ Parameters
662
+ ----------
663
+ x : torch.Tensor
664
+ Tensor of shape ``(..., features)`` with an even final dimension.
665
+
666
+ Returns
667
+ -------
668
+ torch.Tensor
669
+ Same shape, device and dtype as ``x``.
670
+ """
671
+ first, second = x.chunk(2, dim=-1)
672
+ return torch.cat((-second, first), dim=-1)
673
+
674
+
675
+ def rotary_frequencies(
676
+ head_dim: int,
677
+ base: float = 10000.0,
678
+ device: Optional[torch.device] = None,
679
+ dtype: torch.dtype = torch.float32,
680
+ ) -> torch.Tensor:
681
+ """Inverse frequencies of a rotary embedding, ``1 / base ** (2 i / head_dim)``.
682
+
683
+ Parameters
684
+ ----------
685
+ head_dim : int
686
+ Even feature dimension that is rotated.
687
+ base : float, default=10000.0
688
+ Base period (``theta``).
689
+ device : torch.device, optional
690
+ dtype : torch.dtype, default=torch.float32
691
+ Precision of the table; the angles inherit it.
692
+
693
+ Returns
694
+ -------
695
+ torch.Tensor
696
+ Shape ``(head_dim // 2,)``.
697
+ """
698
+ exponent = torch.arange(0, head_dim, 2, device=device, dtype=dtype) / head_dim
699
+ return 1.0 / (base**exponent)
700
+
701
+
702
+ def rotary_angles(
703
+ positions: torch.Tensor, inv_freq: torch.Tensor, interleaved: bool = True
704
+ ) -> torch.Tensor:
705
+ """Rotation angles of each position, laid out to match the feature layout.
706
+
707
+ Parameters
708
+ ----------
709
+ positions : torch.Tensor
710
+ Shape ``(...,)``; same dtype as ``inv_freq`` for exact angles.
711
+ inv_freq : torch.Tensor
712
+ Shape ``(head_dim // 2,)``, from :func:`rotary_frequencies`.
713
+ interleaved : bool, default=True
714
+ ``True`` repeats each angle for its adjacent pair (:func:`rotate_pairs`);
715
+ ``False`` concatenates the angles twice (:func:`rotate_half`).
716
+
717
+ Returns
718
+ -------
719
+ torch.Tensor
720
+ Shape ``(..., head_dim)``; pass ``.cos()`` and ``.sin()`` to
721
+ :func:`apply_rotary`.
722
+ """
723
+ angles = positions.unsqueeze(-1) * inv_freq
724
+ if interleaved:
725
+ return angles.repeat_interleave(2, dim=-1)
726
+ return torch.cat((angles, angles), dim=-1)
727
+
728
+
729
+ def apply_rotary(
730
+ x: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor, interleaved: bool = True
731
+ ) -> torch.Tensor:
732
+ """Rotate ``x`` by the angles whose cosine and sine are given.
733
+
734
+ ``x * cos + rotate(x) * sin``, where ``rotate`` is :func:`rotate_pairs`
735
+ (``interleaved=True``) or :func:`rotate_half`. ``cos`` and ``sin`` must
736
+ broadcast to ``x``; casting is left to the caller.
737
+
738
+ Parameters
739
+ ----------
740
+ x : torch.Tensor
741
+ Shape ``(..., head_dim)``.
742
+ cos, sin : torch.Tensor
743
+ From :func:`rotary_angles`.
744
+ interleaved : bool, default=True
745
+ Feature layout, as in :func:`rotary_angles`.
746
+
747
+ Returns
748
+ -------
749
+ torch.Tensor
750
+ Same shape as ``x``.
751
+ """
752
+ rotated = rotate_pairs(x) if interleaved else rotate_half(x)
753
+ return x * cos + rotated * sin
@@ -0,0 +1,105 @@
1
+ """Cutting a time axis into patches: how many, and padding or cropping to fit."""
2
+
3
+ # Authors: Bruno Aristimunha <b.aristimunha@gmail.com>
4
+ #
5
+ # License: BSD (3-clause)
6
+
7
+ import torch
8
+ import torch.nn.functional as F
9
+
10
+ _ON_NON_DIVISIBLE = ("pad", "crop", "error")
11
+
12
+
13
+ def _check_on_non_divisible(on_non_divisible: str) -> None:
14
+ """Raise a ``ValueError`` for an unknown ``on_non_divisible`` value."""
15
+ if on_non_divisible not in _ON_NON_DIVISIBLE:
16
+ raise ValueError(
17
+ "on_non_divisible must be 'pad', 'crop', or 'error', "
18
+ f"got {on_non_divisible!r}."
19
+ )
20
+
21
+
22
+ def patch_count(
23
+ n_times: int, patch_size: int, on_non_divisible: str = "pad", step: int = 0
24
+ ) -> int:
25
+ """Number of patches cut from ``n_times`` samples.
26
+
27
+ Parameters
28
+ ----------
29
+ n_times : int
30
+ Length of the axis that is patched.
31
+ patch_size : int
32
+ Samples per patch.
33
+ on_non_divisible : {"pad", "crop", "error"}, default="pad"
34
+ A last, incomplete patch is zero-padded (``"pad"``), dropped
35
+ (``"crop"``) or raises a ``ValueError``.
36
+ step : int, default=0
37
+ Distance between patch starts; ``0`` means ``patch_size``
38
+ (non-overlapping).
39
+
40
+ Returns
41
+ -------
42
+ int
43
+ Number of patches.
44
+ """
45
+ if step <= 0:
46
+ step = patch_size
47
+ if n_times < 1:
48
+ raise ValueError(f"n_times must be positive, got {n_times}.")
49
+ if n_times < patch_size:
50
+ if on_non_divisible == "pad":
51
+ return 1
52
+ if on_non_divisible == "crop":
53
+ raise ValueError(
54
+ f"Need at least one full patch of {patch_size} samples, got {n_times}."
55
+ )
56
+ elif (n_times - patch_size) % step == 0:
57
+ return (n_times - patch_size) // step + 1
58
+ elif on_non_divisible != "error":
59
+ return (n_times - patch_size) // step + 1 + (on_non_divisible == "pad")
60
+ raise ValueError(
61
+ f"Time dimension ({n_times}) is not divisible by patch_size ({patch_size})"
62
+ + ("." if step == patch_size else f" with patch step {step}.")
63
+ )
64
+
65
+
66
+ def pad_or_crop_to_patches(
67
+ x: torch.Tensor,
68
+ patch_size: int,
69
+ on_non_divisible: str = "pad",
70
+ step: int = 0,
71
+ min_patches: int = 1,
72
+ center: bool = False,
73
+ ) -> torch.Tensor:
74
+ """Right zero-pad or crop the last axis so the patches tile it.
75
+
76
+ A tiled axis is returned as is. An axis short of ``min_patches`` patches is
77
+ zero-padded up to that many, with half the missing ones (whole steps)
78
+ before it if ``center``.
79
+
80
+ Parameters
81
+ ----------
82
+ x : torch.Tensor
83
+ Shape ``(..., n_times)``.
84
+ patch_size, on_non_divisible, step
85
+ As in :func:`patch_count`.
86
+ min_patches : int, default=1
87
+ Least number of patches on the returned axis.
88
+ center : bool, default=False
89
+ Pad half the missing patches on the left.
90
+
91
+ Returns
92
+ -------
93
+ torch.Tensor
94
+ Shape ``(..., patch_size + (n_patches - 1) * step)``.
95
+ """
96
+ n_patches = patch_count(x.shape[-1], patch_size, on_non_divisible, step)
97
+ step = step if step > 0 else patch_size
98
+ left = 0
99
+ if n_patches < min_patches:
100
+ left = (min_patches - n_patches) // 2 * step if center else 0
101
+ n_patches = min_patches
102
+ target = patch_size + (n_patches - 1) * step
103
+ if target > x.shape[-1]:
104
+ return F.pad(x, (left, target - x.shape[-1] - left))
105
+ return x[..., :target]
@@ -1,7 +1,6 @@
1
1
  # Authors: Cedric Rommel <cedric.rommel@inria.fr>
2
2
  #
3
3
  # License: BSD (3-clause)
4
- import math
5
4
  from typing import Optional
6
5
 
7
6
  import torch
@@ -10,6 +9,7 @@ from mne.utils import warn
10
9
  from torch import nn
11
10
  from torch.nn.utils.parametrize import is_parametrized, register_parametrization
12
11
 
12
+ from braindecode.functional import scaled_dot_product_attention
13
13
  from braindecode.models.base import EEGModuleMixin
14
14
  from braindecode.modules import (
15
15
  CausalConv1d,
@@ -934,20 +934,10 @@ class _MHA(nn.Module):
934
934
  K_ = torch.cat(K.split(self.head_dim, -1), 0) # (B', S, D')
935
935
  V_ = torch.cat(V.split(self.head_dim, -1), 0) # (B', S, D')
936
936
 
937
- # Attention weights of size (num_heads * batch_size, n, m):
938
- # measures how similar each pair of Q and K is.
939
- W = torch.softmax(
940
- Q_.bmm(K_.transpose(-2, -1)) / math.sqrt(self.head_dim),
941
- -1, # (B', D', S)
942
- ) # (B', N, M)
943
-
944
- # Multihead output (batch_size, seq_len, dim):
945
- # weighted sum of V where a value gets more weight if its corresponding
946
- # key has larger dot product with the query.
937
+ # Multihead output (batch_size, seq_len, dim): softmax(Q K^T / sqrt(d)) V
938
+ # per head, heads merged back along the feature axis.
947
939
  H = torch.cat(
948
- (W.bmm(V_)).split( # (B', S, S) # (B', S, D')
949
- batch_size, 0
950
- ), # [(B, S, D')] * num_heads
940
+ scaled_dot_product_attention(Q_, K_, V_, exact=True).split(batch_size, 0),
951
941
  -1,
952
942
  ) # (B, S, D)
953
943
 
@@ -27,15 +27,14 @@
27
27
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
28
  # SOFTWARE.
29
29
 
30
- import math
31
30
  import warnings
32
31
  from copy import deepcopy
33
32
  from numbers import Integral
34
33
 
35
34
  import torch
36
- import torch.nn.functional as F
37
35
  from torch import nn
38
36
 
37
+ from braindecode.functional import scaled_dot_product_attention
39
38
  from braindecode.models.base import EEGModuleMixin
40
39
  from braindecode.modules import CausalConv1d
41
40
 
@@ -411,14 +410,6 @@ class _MRCNN(nn.Module):
411
410
  ##########################################################################################
412
411
 
413
412
 
414
- def _attention(query: torch.Tensor, key: torch.Tensor) -> torch.Tensor:
415
- """Scaled dot product attention weights."""
416
- # d_k - dimension of the query and key vectors
417
- d_k = query.size(-1)
418
- scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(d_k)
419
- return F.softmax(scores, dim=-1) # attention weights
420
-
421
-
422
413
  class _MultiHeadedAttention(nn.Module):
423
414
  def __init__(self, h, d_model, after_reduced_cnn_size, dropout=0.1):
424
415
  """Take in model size and number of heads."""
@@ -464,9 +455,14 @@ class _MultiHeadedAttention(nn.Module):
464
455
  .transpose(1, 2)
465
456
  )
466
457
 
467
- # apply dropout to the *weights*, then the weighted sum
468
- attn = self.dropout(_attention(query, key))
469
- x = torch.matmul(attn, value)
458
+ # exact: the reference op order, same outputs as its hand-written attention
459
+ x = scaled_dot_product_attention(
460
+ query,
461
+ key,
462
+ value,
463
+ dropout_p=self.dropout.p if self.training else 0.0,
464
+ exact=True,
465
+ )
470
466
 
471
467
  # merge heads and project
472
468
  x = x.transpose(1, 2).contiguous().view(nbatches, -1, self.h * self.d_per_head)
@@ -11,10 +11,12 @@ import torch
11
11
  import torch.nn.functional as F
12
12
  from torch import nn
13
13
 
14
- from braindecode.functional import sinusoidal_positional_encoding
14
+ from braindecode.functional import (
15
+ scaled_dot_product_attention,
16
+ sinusoidal_positional_encoding,
17
+ )
15
18
  from braindecode.models.base import EEGModuleMixin
16
19
  from braindecode.models.util import warn_if_sfreq_differs
17
- from braindecode.modules.attention import _scaled_dot_product_attention
18
20
  from braindecode.modules.channels import _resolve
19
21
 
20
22
 
@@ -468,7 +470,7 @@ class _AxisAttention(nn.Module):
468
470
  .unbind(0)
469
471
  )
470
472
  drop = self.att_drop_prob if self.training else 0.0
471
- attended = _scaled_dot_product_attention(
473
+ attended = scaled_dot_product_attention(
472
474
  query, key, value, attn_mask=mask, dropout_p=drop
473
475
  )
474
476
  return attended.transpose(1, 2).reshape(n_seq, length, -1)
@@ -11,12 +11,18 @@ import torch
11
11
  from einops.layers.torch import Rearrange
12
12
  from torch import nn
13
13
 
14
- from braindecode.functional import init_weights_
14
+ from braindecode.functional import (
15
+ apply_rotary,
16
+ init_weights_,
17
+ patch_count,
18
+ rotary_angles,
19
+ rotary_frequencies,
20
+ scaled_dot_product_attention,
21
+ )
22
+ from braindecode.functional.patches import _check_on_non_divisible
15
23
  from braindecode.models.base import EEGModuleMixin
16
24
  from braindecode.models.util import extract_channel_locations_from_chs_info
17
25
  from braindecode.modules import GatedLinearUnit, PatchTokenizer
18
- from braindecode.modules.attention import _scaled_dot_product_attention
19
- from braindecode.modules.blocks import _check_on_non_divisible, _patch_count
20
26
 
21
27
  # Weight initialization of the reference implementation.
22
28
  _init_weights = partial(
@@ -287,7 +293,7 @@ class BaRISTA(EEGModuleMixin, nn.Module, license="other"):
287
293
  # ceil(n_times / patch_size) with "pad"; floor with "crop" (the
288
294
  # reference: trailing samples dropped, raises below one patch); exact
289
295
  # with "error" (raises otherwise). The learned pooling is sized to it.
290
- self.n_patches = _patch_count(self.n_times, patch_size, on_non_divisible)
296
+ self.n_patches = patch_count(self.n_times, patch_size, on_non_divisible)
291
297
 
292
298
  self.patch_tokenizer = PatchTokenizer(
293
299
  patch_size=patch_size,
@@ -609,7 +615,7 @@ class _Transformer(nn.Module):
609
615
  ):
610
616
  super().__init__()
611
617
  head_dim = d_model // num_heads
612
- inv_freq = 1.0 / (10000.0 ** (torch.arange(0, head_dim, 2).float() / head_dim))
618
+ inv_freq = rotary_frequencies(head_dim)
613
619
  self.inv_freq: torch.Tensor
614
620
  self.register_buffer("inv_freq", inv_freq, persistent=False)
615
621
  self.layers = nn.ModuleList(
@@ -633,8 +639,8 @@ class _Transformer(nn.Module):
633
639
  positions = torch.arange(
634
640
  n_patches, device=self.inv_freq.device, dtype=self.inv_freq.dtype
635
641
  )
636
- angles = torch.outer(positions, self.inv_freq)
637
- angles = torch.cat((angles, angles), dim=-1).repeat_interleave(n_chans, dim=0)
642
+ angles = rotary_angles(positions, self.inv_freq, interleaved=False)
643
+ angles = angles.repeat_interleave(n_chans, dim=0)
638
644
  cos = angles.cos()[None, None]
639
645
  sin = angles.sin()[None, None]
640
646
  for layer in self.layers:
@@ -698,20 +704,13 @@ class _RotarySelfAttention(nn.Module):
698
704
  key = self.split_heads(key)
699
705
  value = self.split_heads(value)
700
706
 
701
- query = _apply_rotary(query, cos, sin)
702
- key = _apply_rotary(key, cos, sin)
707
+ cos, sin = cos.to(query.dtype), sin.to(query.dtype)
708
+ query = apply_rotary(query, cos, sin, interleaved=False)
709
+ key = apply_rotary(key, cos, sin, interleaved=False)
703
710
 
704
711
  # Dropout falls on the attention output rather than on the weights,
705
712
  # through dropout_p, because the reference disables the latter outright.
706
- attention = _scaled_dot_product_attention(query, key, value)
713
+ attention = scaled_dot_product_attention(query, key, value)
707
714
  attention = self.dropout(attention)
708
715
  attention = self.merge_heads(attention)
709
716
  return self.o_proj(attention)
710
-
711
-
712
- def _apply_rotary(
713
- x: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor
714
- ) -> torch.Tensor:
715
- """Apply the reference's half-split (not interleaved) rotary embedding."""
716
- first, second = x.chunk(2, dim=-1)
717
- return x * cos.to(x.dtype) + torch.cat((-second, first), dim=-1) * sin.to(x.dtype)