braindecode 1.7.0.dev182642410__tar.gz → 1.7.0.dev183981614__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 (179) hide show
  1. {braindecode-1.7.0.dev182642410/braindecode.egg-info → braindecode-1.7.0.dev183981614}/PKG-INFO +1 -1
  2. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/classifier.py +7 -7
  3. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/functional/__init__.py +4 -0
  4. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/functional/functions.py +39 -2
  5. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/__init__.py +2 -0
  6. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/bendr.py +8 -1
  7. braindecode-1.7.0.dev183981614/braindecode/models/dance.py +368 -0
  8. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/eegminer.py +38 -62
  9. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/reve.py +32 -33
  10. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/summary.csv +1 -0
  11. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/tcn.py +5 -2
  12. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/util.py +22 -0
  13. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/modules/__init__.py +5 -2
  14. braindecode-1.7.0.dev183981614/braindecode/modules/dance_modules.py +333 -0
  15. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/modules/filter.py +16 -10
  16. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/regressor.py +7 -7
  17. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/training/__init__.py +4 -1
  18. braindecode-1.7.0.dev183981614/braindecode/training/losses.py +284 -0
  19. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/training/scoring.py +46 -5
  20. braindecode-1.7.0.dev183981614/braindecode/version.py +1 -0
  21. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614/braindecode.egg-info}/PKG-INFO +1 -1
  22. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode.egg-info/SOURCES.txt +2 -0
  23. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/api.rst +2 -0
  24. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/whats_new.rst +31 -1
  25. braindecode-1.7.0.dev182642410/braindecode/training/losses.py +0 -105
  26. braindecode-1.7.0.dev182642410/braindecode/version.py +0 -1
  27. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/LICENSE.txt +0 -0
  28. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/MANIFEST.in +0 -0
  29. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/NOTICE.txt +0 -0
  30. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/README.rst +0 -0
  31. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/__init__.py +0 -0
  32. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/augmentation/__init__.py +0 -0
  33. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/augmentation/base.py +0 -0
  34. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/augmentation/functional.py +0 -0
  35. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/augmentation/transforms.py +0 -0
  36. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/__init__.py +0 -0
  37. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/base.py +0 -0
  38. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/bbci.py +0 -0
  39. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/bcicomp.py +0 -0
  40. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/bids/__init__.py +0 -0
  41. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/bids/datasets.py +0 -0
  42. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/bids/format.py +0 -0
  43. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/bids/hub.py +0 -0
  44. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/bids/hub_format.py +0 -0
  45. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/bids/hub_io.py +0 -0
  46. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/bids/hub_validation.py +0 -0
  47. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/bids/iterable.py +0 -0
  48. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/chb_mit.py +0 -0
  49. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/collate.py +0 -0
  50. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/mne.py +0 -0
  51. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/moabb.py +0 -0
  52. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/nmt.py +0 -0
  53. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/registry.py +0 -0
  54. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/siena.py +0 -0
  55. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  56. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/sleep_physionet.py +0 -0
  57. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/tuh.py +0 -0
  58. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/utils.py +0 -0
  59. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datasets/xy.py +0 -0
  60. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datautil/__init__.py +0 -0
  61. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datautil/channel_utils.py +0 -0
  62. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datautil/hub_formats.py +0 -0
  63. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datautil/serialization.py +0 -0
  64. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/datautil/util.py +0 -0
  65. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/eegneuralnet.py +0 -0
  66. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/functional/initialization.py +0 -0
  67. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/atcnet.py +0 -0
  68. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/attentionbasenet.py +0 -0
  69. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/attn_sleep.py +0 -0
  70. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/base.py +0 -0
  71. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/biot.py +0 -0
  72. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/brainmodule.py +0 -0
  73. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/cbramod.py +0 -0
  74. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/codebrain.py +0 -0
  75. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/config.py +0 -0
  76. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/contrawr.py +0 -0
  77. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/ctnet.py +0 -0
  78. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/deep4.py +0 -0
  79. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/deepsleepnet.py +0 -0
  80. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/dgcnn.py +0 -0
  81. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/eegconformer.py +0 -0
  82. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/eegdino.py +0 -0
  83. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/eeginception_erp.py +0 -0
  84. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/eeginception_mi.py +0 -0
  85. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/eegitnet.py +0 -0
  86. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/eegnet.py +0 -0
  87. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/eegnex.py +0 -0
  88. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/eegpt.py +0 -0
  89. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/eegsimpleconv.py +0 -0
  90. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/eegsym.py +0 -0
  91. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/eegtcnet.py +0 -0
  92. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/emg2qwerty.py +0 -0
  93. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/fbcnet.py +0 -0
  94. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/fblightconvnet.py +0 -0
  95. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/fbmsnet.py +0 -0
  96. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/hybrid.py +0 -0
  97. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/ifnet.py +0 -0
  98. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/interpolated.py +0 -0
  99. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/labram.py +0 -0
  100. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/luna.py +0 -0
  101. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/medformer.py +0 -0
  102. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/meta_neuromotor.py +0 -0
  103. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/msvtnet.py +0 -0
  104. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/mvpformer.py +0 -0
  105. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/patchedtransformer.py +0 -0
  106. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/sccnet.py +0 -0
  107. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/shallow_fbcsp.py +0 -0
  108. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/signal_jepa.py +0 -0
  109. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/sinc_shallow.py +0 -0
  110. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
  111. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  112. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/sparcnet.py +0 -0
  113. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/sstdpn.py +0 -0
  114. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/steegformer.py +0 -0
  115. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/syncnet.py +0 -0
  116. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/tcformer.py +0 -0
  117. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/tidnet.py +0 -0
  118. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/tsinception.py +0 -0
  119. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/models/usleep.py +0 -0
  120. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/modules/activation.py +0 -0
  121. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/modules/attention.py +0 -0
  122. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/modules/blocks.py +0 -0
  123. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/modules/convolution.py +0 -0
  124. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/modules/interpolation.py +0 -0
  125. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/modules/layers.py +0 -0
  126. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/modules/linear.py +0 -0
  127. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/modules/parametrization.py +0 -0
  128. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/modules/stats.py +0 -0
  129. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/modules/util.py +0 -0
  130. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/modules/wrapper.py +0 -0
  131. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/preprocessing/__init__.py +0 -0
  132. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
  133. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/preprocessing/mne_preprocess.py +0 -0
  134. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/preprocessing/preprocess.py +0 -0
  135. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/preprocessing/util.py +0 -0
  136. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/preprocessing/windowers.py +0 -0
  137. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/samplers/__init__.py +0 -0
  138. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/samplers/base.py +0 -0
  139. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/samplers/ssl.py +0 -0
  140. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/training/callbacks.py +0 -0
  141. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/util.py +0 -0
  142. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/visualization/__init__.py +0 -0
  143. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/visualization/attribution.py +0 -0
  144. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/visualization/confusion_matrices.py +0 -0
  145. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/visualization/frequency.py +0 -0
  146. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/visualization/metrics.py +0 -0
  147. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/visualization/sanity.py +0 -0
  148. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode/visualization/topology.py +0 -0
  149. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode.egg-info/dependency_links.txt +0 -0
  150. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode.egg-info/requires.txt +0 -0
  151. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/braindecode.egg-info/top_level.txt +0 -0
  152. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/Makefile +0 -0
  153. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/_templates/autosummary/class.rst +0 -0
  154. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  155. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/_templates/autosummary/function.rst +0 -0
  156. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  157. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/cite.rst +0 -0
  158. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/conf.py +0 -0
  159. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/help.rst +0 -0
  160. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/index.rst +0 -0
  161. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/install/install.rst +0 -0
  162. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/install/install_pip.rst +0 -0
  163. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/install/install_source.rst +0 -0
  164. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/models/categorization/attention.rst +0 -0
  165. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/models/categorization/channel.rst +0 -0
  166. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/models/categorization/convolution.rst +0 -0
  167. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/models/categorization/filterbank.rst +0 -0
  168. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/models/categorization/gnn.rst +0 -0
  169. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/models/categorization/interpretable.rst +0 -0
  170. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/models/categorization/lbm.rst +0 -0
  171. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/models/categorization/recurrent.rst +0 -0
  172. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/models/categorization/spd.rst +0 -0
  173. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/models/models.rst +0 -0
  174. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/models/models_categorization.rst +0 -0
  175. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/models/models_table.rst +0 -0
  176. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/models/models_visualization.rst +0 -0
  177. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/docs/sg_execution_times.rst +0 -0
  178. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/pyproject.toml +0 -0
  179. {braindecode-1.7.0.dev182642410 → braindecode-1.7.0.dev183981614}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.7.0.dev182642410
3
+ Version: 1.7.0.dev183981614
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
  # Lukas Gemein <l.gemein@gmail.com>
4
4
  # Bruno Aristimunha <b.aristimunha@gmail.com>
5
5
  # Pierre Guetschel <pierre.guetschel@gmail.com>
6
+ # Sarthak Tayal <sarthaktayal2@gmail.com>
6
7
  #
7
8
  # License: BSD (3-clause)
8
9
 
@@ -195,9 +196,7 @@ class EEGClassifier(_EEGNeuralNet, NeuralNetClassifier):
195
196
  return self.predict_proba(X).argmax(1)
196
197
 
197
198
  def predict_trials(self, X, return_targets=True):
198
- """Create trialwise predictions and optionally also return trialwise.
199
-
200
- labels from cropped dataset.
199
+ """Create trialwise predictions from a cropped dataset.
201
200
 
202
201
  Parameters
203
202
  ----------
@@ -212,10 +211,11 @@ class EEGClassifier(_EEGNeuralNet, NeuralNetClassifier):
212
211
  3-dimensional array (n_trials x n_classes x n_predictions), where
213
212
  the number of predictions depend on the chosen window size and the
214
213
  receptive field of the network.
215
- trial_labels : np.ndarray
216
- 2-dimensional array (n_trials x n_targets) where the number of
217
- targets depends on the decoding paradigm and can be either a single
218
- value, multiple values, or a sequence.
214
+ trial_targets : np.ndarray
215
+ Ground-truth targets from the dataset in a 2-dimensional array
216
+ (n_trials x n_targets). Only returned when ``return_targets=True``.
217
+ The number of targets depends on the decoding paradigm and can be
218
+ either a single value, multiple values, or a sequence.
219
219
  """
220
220
  if not self.cropped:
221
221
  warnings.warn(
@@ -5,6 +5,8 @@ from .functions import (
5
5
  dwt_max_level,
6
6
  hilbert_freq,
7
7
  identity,
8
+ iou_1d,
9
+ pairwise_iou_1d,
8
10
  plv_time,
9
11
  safe_log,
10
12
  sinusoidal_positional_encoding,
@@ -20,6 +22,8 @@ __all__ = [
20
22
  "dwt_max_level",
21
23
  "hilbert_freq",
22
24
  "identity",
25
+ "iou_1d",
26
+ "pairwise_iou_1d",
23
27
  "plv_time",
24
28
  "safe_log",
25
29
  "sinusoidal_positional_encoding",
@@ -1,5 +1,6 @@
1
1
  # Authors: Robin Schirrmeister <robintibor@gmail.com>
2
2
  # Bruno Aristimunha <b.aristimunha@gmail.com>
3
+ # Sarthak Tayal <sarthaktayal2@gmail.com>
3
4
  #
4
5
  # License: BSD (3-clause)
5
6
 
@@ -109,7 +110,7 @@ def _get_gaussian_kernel1d(kernel_size: int, sigma: float) -> torch.Tensor:
109
110
  return kernel1d
110
111
 
111
112
 
112
- def hilbert_freq(x, forward_fourier=True):
113
+ def hilbert_freq(x: torch.Tensor, forward_fourier: bool = True) -> torch.Tensor:
113
114
  r"""
114
115
  Compute the Hilbert transform using PyTorch, separating the real and
115
116
  imaginary parts.
@@ -178,7 +179,9 @@ def hilbert_freq(x, forward_fourier=True):
178
179
  return x
179
180
 
180
181
 
181
- def plv_time(x, forward_fourier=True, epsilon: float = 1e-6):
182
+ def plv_time(
183
+ x: torch.Tensor, forward_fourier: bool = True, epsilon: float = 1e-6
184
+ ) -> torch.Tensor:
182
185
  """Compute the Phase Locking Value (PLV) metric in the time domain.
183
186
 
184
187
  The Phase Locking Value (PLV) is a measure of the synchronization between
@@ -257,6 +260,40 @@ def plv_time(x, forward_fourier=True, epsilon: float = 1e-6):
257
260
  return plv_matrix
258
261
 
259
262
 
263
+ # -----------------------------------------------------------------------------
264
+ # DANCE functional helpers
265
+ #
266
+ # Authors: Bruno Aristimunha <b.aristimunha@gmail.com>
267
+ #
268
+ # License: MIT
269
+ #
270
+ # Ported from the DANCE event-detection model (facebookresearch/dance, MIT).
271
+ # -----------------------------------------------------------------------------
272
+
273
+
274
+ def iou_1d(s1, e1, s2, e2, eps: float = 1e-7):
275
+ """ELEMENTWISE 1-D temporal IoU. All four inputs share the same shape S
276
+ (e.g. ``(B, Q)``); returns IoU of shape S. Used by ``DanceLoss`` on the
277
+ matched ``(B, Q)`` spans. For (Q,)x(T,) pairwise IoU use ``pairwise_iou_1d``.
278
+ """
279
+ inter = (torch.minimum(e1, e2) - torch.maximum(s1, s2)).clamp(min=0)
280
+ union = (e1 - s1) + (e2 - s2) - inter
281
+ return inter / (union + eps)
282
+
283
+
284
+ def pairwise_iou_1d(s1, e1, s2, e2, eps: float = 1e-7):
285
+ """PAIRWISE 1-D temporal IoU. ``s1,e1`` shape ``(Q,)``, ``s2,e2`` shape
286
+ ``(T,)``; returns ``(Q, T)`` (broadcast ``[:, None]`` x ``[None, :]``).
287
+ Transcribed from ``dance/matcher.py:33-39`` (``_pairwise_iou``). Used by
288
+ ``HungarianMatcher`` to build the ``(Q, n_targets)`` cost matrix.
289
+ """
290
+ inter_start = torch.maximum(s1[:, None], s2[None, :])
291
+ inter_end = torch.minimum(e1[:, None], e2[None, :])
292
+ inter = (inter_end - inter_start).clamp(min=0)
293
+ union = (e1 - s1)[:, None] + (e2 - s2)[None, :] - inter
294
+ return inter / (union + eps)
295
+
296
+
260
297
  def daubechies_filters(n_vanishing: int) -> torch.Tensor:
261
298
  r"""Daubechies ``db<n_vanishing>`` wavelet decomposition filters.
262
299
 
@@ -11,6 +11,7 @@ from .cbramod import CBraMod
11
11
  from .codebrain import CodeBrain
12
12
  from .contrawr import ContraWR
13
13
  from .ctnet import CTNet
14
+ from .dance import DANCE
14
15
  from .deep4 import Deep4Net
15
16
  from .deepsleepnet import DeepSleepNet
16
17
  from .dgcnn import DGCNN
@@ -86,6 +87,7 @@ __all__ = [
86
87
  "CodeBrain",
87
88
  "ContraWR",
88
89
  "CTNet",
90
+ "DANCE",
89
91
  "Deep4Net",
90
92
  "DeepSleepNet",
91
93
  "BrainModule",
@@ -1,3 +1,8 @@
1
+ # Authors: Bruno Aristimunha <b.aristimunha@gmail.com>
2
+ # Sarthak Tayal <sarthaktayal2@gmail.com>
3
+ #
4
+ # License: BSD (3-clause)
5
+
1
6
  import copy
2
7
 
3
8
  import numpy as np
@@ -435,7 +440,9 @@ class _ConvEncoderBENDR(nn.Module):
435
440
  padding=width
436
441
  // 2, # Correct padding for 'same' output length before stride
437
442
  ),
438
- nn.Dropout2d(dropout), # 2D dropout (matches paper specification)
443
+ # channel-wise dropout (matches paper specification), on
444
+ # (batch, channels, times) activations
445
+ nn.Dropout1d(dropout),
439
446
  nn.GroupNorm(
440
447
  encoder_h // 2, encoder_h
441
448
  ), # Consider making num_groups configurable or ensure encoder_h is divisible by 2
@@ -0,0 +1,368 @@
1
+ # Authors: Bruno Aristimunha <b.aristimunha@gmail.com>
2
+ # Meta Platforms, Inc. and affiliates (original DANCE)
3
+ #
4
+ # License: MIT
5
+ # Adapted from https://github.com/facebookresearch/dance (MIT).
6
+ """``DANCE``: detect-and-classify EEG events (DETR for 1-D EEG)."""
7
+
8
+ from __future__ import annotations
9
+
10
+ import warnings
11
+
12
+ import torch
13
+ from torch import nn
14
+
15
+ from braindecode.models.base import EEGModuleMixin
16
+ from braindecode.models.util import (
17
+ _disable_batch_norm_training_if_batch_size_one, # decorates ``forward``
18
+ )
19
+ from braindecode.models.util import has_valid_locations as _has_valid_locations
20
+ from braindecode.models.util import positions_from_chs_info as _positions_from_chs_info
21
+ from braindecode.modules import ChannelMerger, Perceiver, SimpleConv
22
+ from braindecode.modules.dance_modules import DanceDetrDecoder
23
+
24
+
25
+ class DANCE(EEGModuleMixin, nn.Module):
26
+ r"""DANCE from Lévy et al (2026) [dance]_.
27
+
28
+ :bdg-success:`Convolution` :bdg-info:`Attention/Transformer` :bdg-dark-line:`Channel`
29
+
30
+ DANCE frames EEG decoding as event *set prediction*: a long, unaligned
31
+ window is mapped to a set of events ``(t_start, t_end, class)`` with
32
+ normalized ``[0, 1]`` spans -- DETR for 1-D EEG.
33
+
34
+ .. rubric:: Architecture Overview
35
+
36
+ ``ChannelMerger`` (spatial Fourier attention over electrode positions) ->
37
+ ``SimpleConv`` (dilated conv stack) -> ``Perceiver`` (cross-attention to a
38
+ fixed 256-latent grid) -> a dense head (``forward`` output) and a DETR
39
+ cross-attention decoder (``detect`` output).
40
+
41
+ .. rubric:: Macro Components
42
+
43
+ ``DANCE.conv.merger`` (Spatial ChannelMerger)
44
+ **Operations.** :class:`~braindecode.modules.ChannelMerger` Fourier-embeds
45
+ each electrode's ``(x, y)`` position (:class:`~braindecode.modules.FourierEmb`)
46
+ and computes ``n_virtual_channels`` softmax-attention combinations of the
47
+ input channels, mapping ``(B, n_chans, T) -> (B, n_virtual_channels, T)``.
48
+ Nested inside ``self.conv`` (matching upstream); disabled (``None``) when
49
+ ``chs_info`` has no usable locations. Controlled by ``merger_drop_prob``.
50
+ **Role.** Makes the model montage-agnostic by projecting any electrode
51
+ layout onto a fixed virtual-channel basis.
52
+
53
+ ``DANCE.conv`` (SimpleConv dilated front-end)
54
+ **Operations.** :class:`~braindecode.modules.SimpleConv` runs the nested
55
+ merger, a ``1x1`` ``initial_linear`` projection, then ``conv_depth``
56
+ residual dilated ``Conv1d`` blocks (``nn.ReLU``, dilation accumulating as
57
+ ``int(dilation * conv_dilation_growth)`` per block, same-padding preserves
58
+ ``T``), mapping ``-> (B, embed_dim, T)``.
59
+ **Role.** Builds the temporal feature representation (Défossez lineage).
60
+
61
+ ``DANCE.perceiver`` (Perceiver bottleneck)
62
+ **Operations.** :class:`~braindecode.modules.Perceiver` Fourier-encodes the
63
+ time axis, then cross-attends a fixed ``num_latents``-token learnable grid to
64
+ the conv features over ``perceiver_depth`` blocks, mapping
65
+ ``(B, T, embed_dim) -> (B, num_latents, embed_dim)``.
66
+ **Role.** Makes the model length-agnostic (any ``T`` -> ``num_latents``
67
+ tokens) and forms the detection time-grid (``num_latents / duration``
68
+ tokens/s).
69
+
70
+ ``DANCE.decoder`` (DETR cross-attention decoder)
71
+ **Operations.** ``DanceDetrDecoder`` projects the latents to
72
+ ``decoder_dim``, then ``decoder_depth`` self-/cross-attention layers update
73
+ ``n_queries`` learnable event queries; per-query heads emit class logits and
74
+ sigmoid ``start``/``end`` spans. Used only by :meth:`detect` (not
75
+ :meth:`forward`).
76
+ **Role.** Produces the event-set prediction ``{class, start, end}``.
77
+
78
+ ``DANCE.final_layer`` (dense per-token head)
79
+ **Operations.** ``nn.Linear(embed_dim, n_outputs)`` applied to every latent
80
+ token, mapping ``(B, num_latents, embed_dim) -> (B, num_latents, n_outputs)``.
81
+ **Role.** The :meth:`forward` output (dense per-token class logits) and the
82
+ ``dense`` term consumed by the consistency loss.
83
+
84
+ .. rubric:: Temporal, Spatial, and Spectral Encoding
85
+
86
+ Temporal context comes from the dilated conv stack; spatial structure from
87
+ the Fourier-position channel merge; the Perceiver fourier-encodes the time
88
+ axis before cross-attention.
89
+
90
+ .. rubric:: Additional Mechanisms
91
+
92
+ The DETR decoder uses learnable event queries and emits per-query class
93
+ logits plus sigmoid start/end spans. The dense head provides per-token
94
+ class logits used as ``forward``'s output and for the consistency loss.
95
+
96
+ .. versionadded:: 1.6.1
97
+
98
+ Parameters
99
+ ----------
100
+ n_queries : int, optional
101
+ Number of learnable event queries. The default is ``100``.
102
+ use_channel_merger : bool, optional
103
+ Enable the spatial Fourier ChannelMerger. Auto-disabled if ``chs_info``
104
+ has no usable electrode locations. The default is ``True``.
105
+ n_virtual_channels : int, optional
106
+ Merger output channels. The default is ``270``.
107
+ fourier_emb_dim : int, optional
108
+ Fourier position embedding dim. The default is ``2048``.
109
+ merger_drop_prob : float, optional
110
+ Spatial dropout of the ChannelMerger ONLY (``self.conv.merger``);
111
+ bans whole channels within a random radius during training. The
112
+ default is ``0.2``.
113
+ embed_dim : int, optional
114
+ Conv/Perceiver feature dim. The default is ``128``.
115
+ conv_hidden : int, optional
116
+ SimpleConv hidden width. The default is ``512``.
117
+ conv_depth : int, optional
118
+ Number of dilated conv blocks. The default is ``10``.
119
+ conv_kernel_size : int, optional
120
+ Conv kernel size. The default is ``9``.
121
+ conv_dilation_growth : float, optional
122
+ Per-block dilation growth. The default is ``2.5``.
123
+ conv_initial_linear : int, optional
124
+ 1x1 projection width. The default is ``256``.
125
+ conv_initial_depth : int, optional
126
+ Number of 1x1 projections. The default is ``1``.
127
+ conv_drop_prob : float, optional
128
+ Conv-block dropout knob, exposed for API symmetry. NOTE: the verified
129
+ DANCE config has NO conv dropout, so this maps to no upstream weights
130
+ and does not affect parity; kept for forward-compatibility. The
131
+ default is ``0.2`` (the paper value).
132
+ num_latents : int, optional
133
+ Perceiver latent count (detection token grid). The default is ``256``.
134
+ perceiver_depth : int, optional
135
+ Perceiver cross-attn blocks. The default is ``6``.
136
+ cross_attn_heads : int, optional
137
+ Perceiver cross-attn heads. The default is ``2``.
138
+ latent_attn_heads : int, optional
139
+ Perceiver self-attn heads. The default is ``2``.
140
+ cross_dim_head : int, optional
141
+ Perceiver cross-attn head dim. The default is ``64``.
142
+ latent_dim_head : int, optional
143
+ Perceiver self-attn head dim. The default is ``64``.
144
+ max_freq : float, optional
145
+ Perceiver fourier max frequency. The default is ``10.0``.
146
+ num_freq_bands : int, optional
147
+ Perceiver fourier bands. The default is ``6``.
148
+ decoder_dim : int, optional
149
+ DETR decoder dim. The default is ``256``.
150
+ decoder_depth : int, optional
151
+ DETR decoder layers. The default is ``4``.
152
+ decoder_heads : int, optional
153
+ DETR decoder heads. The default is ``4``.
154
+ activation : type[nn.Module], optional
155
+ Accepted for interface symmetry but currently INERT: it is forwarded to
156
+ ``self.decoder`` yet the decoder feed-forward hardwires GEGLU
157
+ (:class:`~braindecode.modules.dance_modules._FeedForward`), and the
158
+ ``SimpleConv`` front-end hardcodes ``nn.ReLU`` to match upstream. No
159
+ submodule reads it today. The default is ``nn.GELU``.
160
+ drop_prob : float, optional
161
+ Dropout applied to the raw input (``self.input_drop``) and inside the
162
+ DETR decoder (``self.decoder``). Does NOT touch the merger (use
163
+ ``merger_drop_prob``) or the conv stack (no conv dropout upstream).
164
+ The default is ``0.1``.
165
+
166
+ References
167
+ ----------
168
+ .. [dance] Lévy, Banville, Rapin, King, Moreau, d'Ascoli (2026). DANCE:
169
+ Detect and Classify Events in EEG. arXiv:2605.10688.
170
+ .. [defossez2023] Défossez et al. (2023). Decoding speech from
171
+ non-invasive brain recordings.
172
+ .. [perceiver2021] Jaegle et al. (2021). Perceiver: General perception
173
+ with iterative attention.
174
+ .. [detr2020] Carion et al. (2020). End-to-end object detection with
175
+ transformers.
176
+ """
177
+
178
+ def __init__(
179
+ self,
180
+ n_outputs=None,
181
+ n_chans=None,
182
+ chs_info=None,
183
+ n_times=None,
184
+ input_window_seconds=None,
185
+ sfreq=None,
186
+ *,
187
+ n_queries: int = 100,
188
+ use_channel_merger: bool = True,
189
+ n_virtual_channels: int = 270,
190
+ fourier_emb_dim: int = 2048,
191
+ merger_drop_prob: float = 0.2,
192
+ embed_dim: int = 128,
193
+ conv_hidden: int = 512,
194
+ conv_depth: int = 10,
195
+ conv_kernel_size: int = 9,
196
+ conv_dilation_growth: float = 2.5,
197
+ conv_initial_linear: int = 256,
198
+ conv_initial_depth: int = 1,
199
+ conv_drop_prob: float = 0.2,
200
+ num_latents: int = 256,
201
+ perceiver_depth: int = 6,
202
+ cross_attn_heads: int = 2,
203
+ latent_attn_heads: int = 2,
204
+ cross_dim_head: int = 64,
205
+ latent_dim_head: int = 64,
206
+ max_freq: float = 10.0,
207
+ num_freq_bands: int = 6,
208
+ decoder_dim: int = 256,
209
+ decoder_depth: int = 4,
210
+ decoder_heads: int = 4,
211
+ activation: type[nn.Module] = nn.GELU,
212
+ drop_prob: float = 0.1,
213
+ ):
214
+ super().__init__(
215
+ n_outputs=n_outputs,
216
+ n_chans=n_chans,
217
+ chs_info=chs_info,
218
+ n_times=n_times,
219
+ input_window_seconds=input_window_seconds,
220
+ sfreq=sfreq,
221
+ )
222
+ del n_outputs, n_chans, sfreq, n_times, input_window_seconds, chs_info
223
+
224
+ self.num_latents = num_latents
225
+ self.n_queries = n_queries
226
+ self.embed_dim = embed_dim
227
+
228
+ # Decide the merger up front (fall back to no-merger if no locations).
229
+ if use_channel_merger and not _has_valid_locations(self.chs_info):
230
+ warnings.warn(
231
+ "DANCE: chs_info has no usable electrode locations "
232
+ "('loc' missing or all-zero); disabling the ChannelMerger "
233
+ "(use_channel_merger=False).",
234
+ UserWarning,
235
+ )
236
+ use_channel_merger = False
237
+ # Public flag mirroring the fallback decision (``self.conv.merger`` is the
238
+ # source of truth in forward); kept for introspection/tests.
239
+ self.use_channel_merger = use_channel_merger
240
+
241
+ # The merger is NESTED INSIDE SimpleConv (self.conv.merger), matching
242
+ # upstream SimpleConvModel's call path and state_dict layout. There is
243
+ # NO top-level self.channel_merger. The (n_chans, 2) positions buffer is
244
+ # derived from chs_info and broadcast in forward; subject_ids is always
245
+ # None (braindecode has no subjects; per_subject=False).
246
+ merger = None
247
+ if use_channel_merger:
248
+ positions = _positions_from_chs_info(self.chs_info)
249
+ self.register_buffer(
250
+ "channel_positions",
251
+ torch.as_tensor(positions, dtype=torch.float32),
252
+ persistent=False,
253
+ )
254
+ merger = ChannelMerger(
255
+ out_channels=n_virtual_channels,
256
+ pos_dim=fourier_emb_dim,
257
+ dropout=merger_drop_prob,
258
+ )
259
+
260
+ self.input_drop = nn.Dropout(drop_prob)
261
+ self.conv = SimpleConv(
262
+ in_channels=self.n_chans,
263
+ out_channels=embed_dim,
264
+ hidden=conv_hidden,
265
+ depth=conv_depth,
266
+ kernel_size=conv_kernel_size,
267
+ dilation_growth=conv_dilation_growth,
268
+ initial_linear=conv_initial_linear,
269
+ initial_depth=conv_initial_depth,
270
+ drop_prob=conv_drop_prob,
271
+ activation=nn.ReLU,
272
+ merger=merger,
273
+ )
274
+ # The conv stack is SAME-padded, so it preserves length for any T >= 1;
275
+ # the dilated receptive field is not an input-length requirement. The
276
+ # genuine minimum is one first-block kernel (dilation 1), so the guard
277
+ # uses ``conv_kernel_size`` rather than the full receptive field.
278
+ self._min_n_times = conv_kernel_size
279
+ self.perceiver = Perceiver(
280
+ input_dim=embed_dim,
281
+ num_latents=num_latents,
282
+ latent_dim=embed_dim,
283
+ depth=perceiver_depth,
284
+ cross_heads=cross_attn_heads,
285
+ latent_heads=latent_attn_heads,
286
+ cross_dim_head=cross_dim_head,
287
+ latent_dim_head=latent_dim_head,
288
+ max_freq=max_freq,
289
+ num_freq_bands=num_freq_bands,
290
+ )
291
+ self.decoder = DanceDetrDecoder(
292
+ input_dim=embed_dim,
293
+ dim=decoder_dim,
294
+ depth=decoder_depth,
295
+ heads=decoder_heads,
296
+ n_queries=n_queries,
297
+ n_outputs=self.n_outputs,
298
+ drop_prob=drop_prob,
299
+ activation=activation,
300
+ )
301
+ # final_layer LAST so it lands in the last two named_children(); init
302
+ # weights AFTER it exists so the dense head gets the custom init too.
303
+ self.final_layer = nn.Linear(embed_dim, self.n_outputs)
304
+ self.apply(self._init_weights)
305
+
306
+ @staticmethod
307
+ def _init_weights(module: nn.Module) -> None:
308
+ if isinstance(module, nn.Linear):
309
+ nn.init.trunc_normal_(module.weight, std=0.02)
310
+ if module.bias is not None:
311
+ nn.init.zeros_(module.bias)
312
+ elif isinstance(module, nn.LayerNorm):
313
+ nn.init.ones_(module.weight)
314
+ nn.init.zeros_(module.bias)
315
+
316
+ def _encode(self, x: torch.Tensor) -> torch.Tensor:
317
+ if x.ndim != 3 or x.shape[-2] != self.n_chans:
318
+ raise ValueError(
319
+ f"expected (batch, {self.n_chans}, T) input; got {tuple(x.shape)}."
320
+ )
321
+ if x.shape[-1] < self._min_n_times:
322
+ raise ValueError(
323
+ f"n_times={x.shape[-1]} is shorter than the minimum input "
324
+ f"length ({self._min_n_times} samples = one conv kernel)."
325
+ )
326
+ x = self.input_drop(x)
327
+ # The merger is nested inside self.conv; pass positions through it.
328
+ # subject_ids is always None (braindecode has no subjects).
329
+ if self.conv.merger is not None:
330
+ pos = self.channel_positions.unsqueeze(0).expand(x.size(0), -1, -1)
331
+ x = self.conv(x, positions=pos) # merger -> initial_linear -> blocks
332
+ else:
333
+ x = self.conv(x) # (B, embed_dim, T)
334
+ x = x.transpose(2, 1) # (B, T, embed_dim)
335
+ x = self.perceiver(x) # (B, num_latents, embed_dim)
336
+ return x
337
+
338
+ @_disable_batch_norm_training_if_batch_size_one
339
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
340
+ latents = self._encode(x) # (B, num_latents, embed_dim)
341
+ return self.final_layer(latents) # (B, num_latents, n_outputs)
342
+
343
+ @_disable_batch_norm_training_if_batch_size_one
344
+ def detect(self, x: torch.Tensor) -> dict:
345
+ latents = self._encode(x) # (B, num_latents, embed_dim)
346
+ events = self.decoder(latents) # {class, start, end}
347
+ events["dense"] = self.final_layer(latents) # (B, num_latents, n_outputs)
348
+ return events
349
+
350
+ def reset_head(self, n_outputs: int) -> None:
351
+ """Replace the dense head and the DETR class head for a new ``n_outputs``."""
352
+ if n_outputs <= 0:
353
+ raise ValueError(f"n_outputs must be positive; got {n_outputs}.")
354
+ old = self.final_layer
355
+ self.final_layer = nn.Linear(old.in_features, n_outputs).to(
356
+ device=old.weight.device, dtype=old.weight.dtype
357
+ )
358
+ ch = self.decoder.class_head
359
+ self.decoder.class_head = nn.Linear(ch.in_features, n_outputs).to(
360
+ device=ch.weight.device, dtype=ch.weight.dtype
361
+ )
362
+ self._n_outputs = n_outputs
363
+ init_kwargs = getattr(self, "_braindecode_init_kwargs", None)
364
+ if init_kwargs is not None and "n_outputs" in init_kwargs:
365
+ init_kwargs["n_outputs"] = n_outputs
366
+ hub_config = getattr(self, "_hub_mixin_config", None)
367
+ if hub_config is not None and "n_outputs" in hub_config:
368
+ hub_config["n_outputs"] = n_outputs
@@ -5,10 +5,9 @@
5
5
  * https://www.ipo.gov.uk/p-ipsum/Case/ApplicationNumber/GB2113420.0
6
6
  """
7
7
 
8
- from functools import partial
8
+ # Authors: Sarthak Tayal <sarthaktayal2@gmail.com>
9
9
 
10
10
  import torch
11
- from einops.layers.torch import Rearrange
12
11
  from torch import nn
13
12
 
14
13
  import braindecode.functional as F
@@ -19,6 +18,36 @@ from braindecode.modules import GeneralizedGaussianFilter
19
18
  _eeg_miner_methods = ["mag", "corr", "plv"]
20
19
 
21
20
 
21
+ class _EEGMinerFeatures(nn.Module):
22
+ def __init__(self, method, n_chans, n_filters, n_times):
23
+ super().__init__()
24
+ self.method = method
25
+ self.n_chans = n_chans
26
+ self.n_filters = n_filters
27
+ self.n_times = n_times
28
+ triu = torch.triu_indices(n_chans, n_chans, 1)
29
+ self.register_buffer("triu_row", triu[0], persistent=False)
30
+ self.register_buffer("triu_col", triu[1], persistent=False)
31
+
32
+ def forward(self, x):
33
+ if self.method == "mag":
34
+ return torch.sqrt((x * x).mean(dim=-1))
35
+ if self.method == "corr":
36
+ x = x.reshape(
37
+ x.shape[0], self.n_chans, self.n_filters, self.n_times
38
+ ).transpose(-3, -2)
39
+ x = (x - x.mean(dim=-1, keepdim=True)) / torch.sqrt(
40
+ x.var(dim=-1, keepdim=True) + 1e-6
41
+ )
42
+ x = torch.matmul(x, x.transpose(-2, -1)) / x.shape[-1]
43
+ x = x.permute(0, 2, 3, 1).abs()
44
+ else:
45
+ x = x.transpose(-4, -3)
46
+ x = F.plv_time(x, forward_fourier=False)
47
+ x = x.permute(0, 2, 3, 1)
48
+ return x[:, self.triu_row, self.triu_col, :]
49
+
50
+
22
51
  class EEGMiner(EEGModuleMixin, nn.Module):
23
52
  r"""EEGMiner from Ludwig et al (2024) [eegminer]_.
24
53
 
@@ -168,24 +197,18 @@ class EEGMiner(EEGModuleMixin, nn.Module):
168
197
  )
169
198
 
170
199
  # Forward method
200
+ self.ensure_dim = nn.Identity()
171
201
  if self.method == "mag":
172
- self.method_forward = self._apply_mag_forward
173
202
  self.n_features = self.n_chans * self.n_filters
174
- self.ensure_dim = nn.Identity()
175
203
  elif self.method == "corr":
176
- self.method_forward = partial(
177
- self._apply_corr_forward,
178
- n_chans=self.n_chans,
179
- n_filters=self.n_filters,
180
- n_times=self.n_times,
181
- )
182
204
  self.n_features = self.n_filters * self.n_chans * (self.n_chans - 1) // 2
183
- self.ensure_dim = nn.Identity()
184
205
  elif self.method == "plv":
185
- self.method_forward = partial(self._apply_plv, n_chans=self.n_chans)
186
- self.ensure_dim = Rearrange("... d -> ... 1 d")
206
+ self.ensure_dim = nn.Unflatten(-1, (1, self.n_times))
187
207
  self.n_features = (self.n_filters * self.n_chans * (self.n_chans - 1)) // 2
188
208
 
209
+ self.feature_layer = _EEGMinerFeatures(
210
+ self.method, self.n_chans, self.n_filters, self.n_times
211
+ )
189
212
  self.flatten_layer = nn.Flatten()
190
213
  # Classifier
191
214
  self.batch_layer = nn.BatchNorm1d(self.n_features, affine=False)
@@ -195,64 +218,17 @@ class EEGMiner(EEGModuleMixin, nn.Module):
195
218
  @_disable_batch_norm_training_if_batch_size_one
196
219
  def forward(self, x):
197
220
  """x: (batch, electrodes, time)"""
198
- batch = x.shape[0]
199
221
  x = self.ensure_dim(x)
200
222
  # Apply Gaussian filters in frequency domain
201
223
  # x -> (batch, electrodes * filters, time)
202
224
  x = self.filter(x)
203
225
 
204
- x = self.method_forward(x=x, batch=batch)
226
+ x = self.feature_layer(x)
205
227
  # Classifier
206
228
  # Note that the order of dimensions before flattening the feature vector is important
207
229
  # for attributing feature weights during interpretation.
208
- x = x.reshape(batch, self.n_features)
230
+ x = x.reshape(x.shape[0], self.n_features)
209
231
  x = self.batch_layer(x)
210
232
  x = self.final_layer(x)
211
233
 
212
234
  return x
213
-
214
- @staticmethod
215
- def _apply_mag_forward(x, batch=None):
216
- # Signal magnitude
217
- x = x * x
218
- x = x.mean(dim=-1)
219
- x = torch.sqrt(x)
220
- return x
221
-
222
- @staticmethod
223
- def _apply_corr_forward(
224
- x, batch, n_chans, n_filters, n_times, epilson: float = 1e-6
225
- ):
226
- x = x.reshape(batch, n_chans, n_filters, n_times).transpose(-3, -2)
227
- x = (x - x.mean(dim=-1, keepdim=True)) / torch.sqrt(
228
- x.var(dim=-1, keepdim=True) + epilson
229
- )
230
- x = torch.matmul(x, x.transpose(-2, -1)) / x.shape[-1]
231
- # Original tensor shape: [batch, n_filters, chans, chans]
232
- x = x.permute(0, 2, 3, 1)
233
- # New tensor shape: [batch, chans, chans, n_filters]
234
- # move filter channels to the end
235
- x = x.abs()
236
-
237
- # Get upper triu of symmetric connectivity matrix
238
- triu = torch.triu_indices(n_chans, n_chans, 1)
239
- x = x[:, triu[0], triu[1], :]
240
-
241
- return x
242
-
243
- @staticmethod
244
- def _apply_plv(x, n_chans, batch=None):
245
- # Compute PLV connectivity
246
- # x -> (batch, electrodes, electrodes, filters)
247
- x = x.transpose(-4, -3) # swap electrodes and filters
248
- # adjusting to compute the plv
249
- x = F.plv_time(x, forward_fourier=False)
250
- # batch, number of filters, connectivity matrix
251
- # [batch, n_filters, chans, chans]
252
- x = x.permute(0, 2, 3, 1)
253
- # [batch, chans, chans, n_filters]
254
-
255
- # Get upper triu of symmetric connectivity matrix
256
- triu = torch.triu_indices(n_chans, n_chans, 1)
257
- x = x[:, triu[0], triu[1], :]
258
- return x