braindecode 1.7.0.dev182642410__tar.gz → 1.8.0.dev580__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 (180) hide show
  1. {braindecode-1.7.0.dev182642410/braindecode.egg-info → braindecode-1.8.0.dev580}/PKG-INFO +1 -1
  2. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/classifier.py +9 -8
  3. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/sleep_physionet.py +9 -3
  4. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/eegneuralnet.py +4 -2
  5. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/functional/__init__.py +4 -0
  6. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/functional/functions.py +39 -2
  7. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/__init__.py +4 -0
  8. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/bendr.py +8 -1
  9. braindecode-1.8.0.dev580/braindecode/models/dance.py +368 -0
  10. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/eegminer.py +38 -62
  11. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/fblightconvnet.py +31 -4
  12. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/reve.py +32 -33
  13. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/summary.csv +2 -0
  14. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/tcn.py +5 -2
  15. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/util.py +31 -0
  16. braindecode-1.8.0.dev580/braindecode/models/zuna.py +612 -0
  17. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/modules/__init__.py +5 -2
  18. braindecode-1.8.0.dev580/braindecode/modules/dance_modules.py +333 -0
  19. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/modules/filter.py +16 -10
  20. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/preprocessing/eegprep_preprocess.py +1 -1
  21. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/regressor.py +9 -8
  22. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/training/__init__.py +4 -1
  23. braindecode-1.8.0.dev580/braindecode/training/losses.py +284 -0
  24. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/training/scoring.py +46 -5
  25. braindecode-1.8.0.dev580/braindecode/version.py +1 -0
  26. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580/braindecode.egg-info}/PKG-INFO +1 -1
  27. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode.egg-info/SOURCES.txt +3 -0
  28. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/api.rst +3 -0
  29. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/whats_new.rst +97 -2
  30. braindecode-1.7.0.dev182642410/braindecode/training/losses.py +0 -105
  31. braindecode-1.7.0.dev182642410/braindecode/version.py +0 -1
  32. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/LICENSE.txt +0 -0
  33. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/MANIFEST.in +0 -0
  34. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/NOTICE.txt +0 -0
  35. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/README.rst +0 -0
  36. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/__init__.py +0 -0
  37. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/augmentation/__init__.py +0 -0
  38. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/augmentation/base.py +0 -0
  39. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/augmentation/functional.py +0 -0
  40. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/augmentation/transforms.py +0 -0
  41. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/__init__.py +0 -0
  42. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/base.py +0 -0
  43. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/bbci.py +0 -0
  44. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/bcicomp.py +0 -0
  45. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/bids/__init__.py +0 -0
  46. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/bids/datasets.py +0 -0
  47. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/bids/format.py +0 -0
  48. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/bids/hub.py +0 -0
  49. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/bids/hub_format.py +0 -0
  50. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/bids/hub_io.py +0 -0
  51. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/bids/hub_validation.py +0 -0
  52. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/bids/iterable.py +0 -0
  53. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/chb_mit.py +0 -0
  54. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/collate.py +0 -0
  55. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/mne.py +0 -0
  56. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/moabb.py +0 -0
  57. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/nmt.py +0 -0
  58. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/registry.py +0 -0
  59. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/siena.py +0 -0
  60. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  61. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/tuh.py +0 -0
  62. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/utils.py +0 -0
  63. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datasets/xy.py +0 -0
  64. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datautil/__init__.py +0 -0
  65. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datautil/channel_utils.py +0 -0
  66. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datautil/hub_formats.py +0 -0
  67. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datautil/serialization.py +0 -0
  68. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/datautil/util.py +0 -0
  69. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/functional/initialization.py +0 -0
  70. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/atcnet.py +0 -0
  71. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/attentionbasenet.py +0 -0
  72. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/attn_sleep.py +0 -0
  73. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/base.py +0 -0
  74. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/biot.py +0 -0
  75. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/brainmodule.py +0 -0
  76. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/cbramod.py +0 -0
  77. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/codebrain.py +0 -0
  78. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/config.py +0 -0
  79. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/contrawr.py +0 -0
  80. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/ctnet.py +0 -0
  81. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/deep4.py +0 -0
  82. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/deepsleepnet.py +0 -0
  83. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/dgcnn.py +0 -0
  84. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/eegconformer.py +0 -0
  85. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/eegdino.py +0 -0
  86. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/eeginception_erp.py +0 -0
  87. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/eeginception_mi.py +0 -0
  88. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/eegitnet.py +0 -0
  89. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/eegnet.py +0 -0
  90. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/eegnex.py +0 -0
  91. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/eegpt.py +0 -0
  92. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/eegsimpleconv.py +0 -0
  93. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/eegsym.py +0 -0
  94. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/eegtcnet.py +0 -0
  95. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/emg2qwerty.py +0 -0
  96. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/fbcnet.py +0 -0
  97. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/fbmsnet.py +0 -0
  98. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/hybrid.py +0 -0
  99. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/ifnet.py +0 -0
  100. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/interpolated.py +0 -0
  101. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/labram.py +0 -0
  102. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/luna.py +0 -0
  103. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/medformer.py +0 -0
  104. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/meta_neuromotor.py +0 -0
  105. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/msvtnet.py +0 -0
  106. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/mvpformer.py +0 -0
  107. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/patchedtransformer.py +0 -0
  108. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/sccnet.py +0 -0
  109. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/shallow_fbcsp.py +0 -0
  110. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/signal_jepa.py +0 -0
  111. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/sinc_shallow.py +0 -0
  112. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
  113. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  114. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/sparcnet.py +0 -0
  115. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/sstdpn.py +0 -0
  116. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/steegformer.py +0 -0
  117. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/syncnet.py +0 -0
  118. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/tcformer.py +0 -0
  119. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/tidnet.py +0 -0
  120. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/tsinception.py +0 -0
  121. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/models/usleep.py +0 -0
  122. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/modules/activation.py +0 -0
  123. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/modules/attention.py +0 -0
  124. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/modules/blocks.py +0 -0
  125. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/modules/convolution.py +0 -0
  126. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/modules/interpolation.py +0 -0
  127. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/modules/layers.py +0 -0
  128. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/modules/linear.py +0 -0
  129. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/modules/parametrization.py +0 -0
  130. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/modules/stats.py +0 -0
  131. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/modules/util.py +0 -0
  132. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/modules/wrapper.py +0 -0
  133. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/preprocessing/__init__.py +0 -0
  134. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/preprocessing/mne_preprocess.py +0 -0
  135. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/preprocessing/preprocess.py +0 -0
  136. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/preprocessing/util.py +0 -0
  137. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/preprocessing/windowers.py +0 -0
  138. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/samplers/__init__.py +0 -0
  139. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/samplers/base.py +0 -0
  140. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/samplers/ssl.py +0 -0
  141. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/training/callbacks.py +0 -0
  142. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/util.py +0 -0
  143. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/visualization/__init__.py +0 -0
  144. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/visualization/attribution.py +0 -0
  145. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/visualization/confusion_matrices.py +0 -0
  146. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/visualization/frequency.py +0 -0
  147. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/visualization/metrics.py +0 -0
  148. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/visualization/sanity.py +0 -0
  149. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode/visualization/topology.py +0 -0
  150. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode.egg-info/dependency_links.txt +0 -0
  151. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode.egg-info/requires.txt +0 -0
  152. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/braindecode.egg-info/top_level.txt +0 -0
  153. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/Makefile +0 -0
  154. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/_templates/autosummary/class.rst +0 -0
  155. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  156. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/_templates/autosummary/function.rst +0 -0
  157. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  158. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/cite.rst +0 -0
  159. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/conf.py +0 -0
  160. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/help.rst +0 -0
  161. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/index.rst +0 -0
  162. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/install/install.rst +0 -0
  163. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/install/install_pip.rst +0 -0
  164. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/install/install_source.rst +0 -0
  165. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/models/categorization/attention.rst +0 -0
  166. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/models/categorization/channel.rst +0 -0
  167. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/models/categorization/convolution.rst +0 -0
  168. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/models/categorization/filterbank.rst +0 -0
  169. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/models/categorization/gnn.rst +0 -0
  170. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/models/categorization/interpretable.rst +0 -0
  171. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/models/categorization/lbm.rst +0 -0
  172. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/models/categorization/recurrent.rst +0 -0
  173. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/models/categorization/spd.rst +0 -0
  174. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/models/models.rst +0 -0
  175. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/models/models_categorization.rst +0 -0
  176. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/models/models_table.rst +0 -0
  177. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/models/models_visualization.rst +0 -0
  178. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/docs/sg_execution_times.rst +0 -0
  179. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/pyproject.toml +0 -0
  180. {braindecode-1.7.0.dev182642410 → braindecode-1.8.0.dev580}/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.8.0.dev580
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(
@@ -228,8 +228,9 @@ class EEGClassifier(_EEGNeuralNet, NeuralNetClassifier):
228
228
  if return_targets:
229
229
  return preds, X.get_metadata()["target"].to_numpy()
230
230
  return preds
231
+ self.check_is_fitted()
231
232
  return predict_trials(
232
- module=self.module,
233
+ module=self.module_,
233
234
  dataset=X,
234
235
  return_targets=return_targets,
235
236
  batch_size=self.batch_size,
@@ -117,9 +117,15 @@ class SleepPhysionet(BaseConcatDataset):
117
117
  sleep_event_inds = np.where(mask)[0]
118
118
 
119
119
  # Crop raw
120
- tmin = annots[int(sleep_event_inds[0])]["onset"] - crop_wake_mins * 60
121
- tmax = annots[int(sleep_event_inds[-1])]["onset"] + crop_wake_mins * 60
122
- raw.crop(tmin=max(tmin, raw.times[0]), tmax=min(tmax, raw.times[-1]))
120
+ a_tmin = annots[sleep_event_inds[0]]
121
+ a_tmax = annots[sleep_event_inds[-1]]
122
+ tmin = a_tmin["onset"] - crop_wake_mins * 60
123
+ tmax = a_tmax["onset"] + a_tmax["duration"] + crop_wake_mins * 60
124
+ raw.crop(
125
+ tmin=max(tmin, raw.times[0]),
126
+ tmax=min(tmax, raw.times[-1] + 1 / raw.info["sfreq"]),
127
+ include_tmax=False,
128
+ )
123
129
 
124
130
  # Rename EEG channels
125
131
  ch_names = {i: i.replace("EEG ", "") for i in raw.ch_names if "EEG" in i}
@@ -1,5 +1,6 @@
1
1
  # Authors: Bruno Aristimunha <b.aristimunha@gmail.com>
2
2
  # Pierre Guetschel <pierre.guetschel@gmail.com>
3
+ # Sarthak Tayal <sarthaktayal2@gmail.com>
3
4
  #
4
5
  # License: BSD (3-clause)
5
6
 
@@ -126,7 +127,8 @@ class _EEGNeuralNet(NeuralNet, abc.ABC):
126
127
  self._last_window_inds_ = None
127
128
 
128
129
  def predict_with_window_inds_and_ys(self, dataset):
129
- self.module.eval()
130
+ # self.module can still be a name or a class, self.module_ is the built one
131
+ self.module_.eval()
130
132
  preds = []
131
133
  i_window_in_trials = []
132
134
  i_window_stops = []
@@ -142,7 +144,7 @@ class _EEGNeuralNet(NeuralNet, abc.ABC):
142
144
  i_window_in_trials.append(i[0].cpu().numpy())
143
145
  i_window_stops.append(i[2].cpu().numpy())
144
146
  with torch.no_grad():
145
- preds.append(to_numpy(self.module.forward(X.to(self.device))))
147
+ preds.append(to_numpy(self.module_.forward(X.to(self.device))))
146
148
  window_ys.append(y.cpu().numpy())
147
149
  preds = np.concatenate(preds)
148
150
  i_window_in_trials = np.concatenate(i_window_in_trials)
@@ -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
@@ -70,6 +71,7 @@ from .util import (
70
71
  models_mandatory_parameters,
71
72
  positions_from_chs_info,
72
73
  )
74
+ from .zuna import ZUNA
73
75
 
74
76
  # Call this last in order to make sure the dataset list is populated with
75
77
  # the models imported in this file.
@@ -86,6 +88,7 @@ __all__ = [
86
88
  "CodeBrain",
87
89
  "ContraWR",
88
90
  "CTNet",
91
+ "DANCE",
89
92
  "Deep4Net",
90
93
  "DeepSleepNet",
91
94
  "BrainModule",
@@ -143,6 +146,7 @@ __all__ = [
143
146
  "TIDNet",
144
147
  "TSception",
145
148
  "USleep",
149
+ "ZUNA",
146
150
  "build_model_config",
147
151
  "_init_models_dict",
148
152
  "models_mandatory_parameters",
@@ -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