braindecode 1.8.1.dev183052608__tar.gz → 1.8.1.dev183240691__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 (217) hide show
  1. {braindecode-1.8.1.dev183052608/braindecode.egg-info → braindecode-1.8.1.dev183240691}/PKG-INFO +1 -1
  2. braindecode-1.8.1.dev183240691/braindecode/__init__.py +53 -0
  3. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/base.py +10 -6
  4. braindecode-1.8.1.dev183240691/braindecode/models/__init__.py +133 -0
  5. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/config.py +0 -5
  6. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/eegconformer.py +66 -1
  7. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/labram.py +1 -5
  8. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/luna.py +6 -6
  9. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/util.py +41 -17
  10. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/util.py +2 -1
  11. braindecode-1.8.1.dev183240691/braindecode/version.py +1 -0
  12. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691/braindecode.egg-info}/PKG-INFO +1 -1
  13. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/whats_new.rst +36 -0
  14. braindecode-1.8.1.dev183052608/braindecode/__init__.py +0 -9
  15. braindecode-1.8.1.dev183052608/braindecode/models/__init__.py +0 -197
  16. braindecode-1.8.1.dev183052608/braindecode/version.py +0 -1
  17. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/LICENSE.txt +0 -0
  18. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/MANIFEST.in +0 -0
  19. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/NOTICE.txt +0 -0
  20. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/README.rst +0 -0
  21. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/augmentation/__init__.py +0 -0
  22. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/augmentation/base.py +0 -0
  23. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/augmentation/functional.py +0 -0
  24. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/augmentation/transforms.py +0 -0
  25. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/classifier.py +0 -0
  26. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/__init__.py +0 -0
  27. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/_notebook_viewer.py +0 -0
  28. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/bbci.py +0 -0
  29. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/bcicomp.py +0 -0
  30. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/bids/__init__.py +0 -0
  31. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/bids/datasets.py +0 -0
  32. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/bids/hub.py +0 -0
  33. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/bids/hub_format.py +0 -0
  34. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/bids/hub_io.py +0 -0
  35. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/bids/hub_validation.py +0 -0
  36. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/bids/iterable.py +0 -0
  37. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/chb_mit.py +0 -0
  38. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/collate.py +0 -0
  39. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/mne.py +0 -0
  40. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/moabb.py +0 -0
  41. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/nmt.py +0 -0
  42. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/registry.py +0 -0
  43. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/siena.py +0 -0
  44. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  45. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/sleep_physionet.py +0 -0
  46. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/tuh.py +0 -0
  47. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/utils.py +0 -0
  48. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datasets/xy.py +0 -0
  49. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datautil/__init__.py +0 -0
  50. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datautil/channel_utils.py +0 -0
  51. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datautil/hub_formats.py +0 -0
  52. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datautil/serialization.py +0 -0
  53. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/datautil/util.py +0 -0
  54. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/eegneuralnet.py +0 -0
  55. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/functional/__init__.py +0 -0
  56. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/functional/_lfilter.py +0 -0
  57. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/functional/_real_dft.py +0 -0
  58. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/functional/attention.py +0 -0
  59. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/functional/channel_mask.py +0 -0
  60. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/functional/functions.py +0 -0
  61. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/functional/initialization.py +0 -0
  62. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/functional/patches.py +0 -0
  63. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/atcnet.py +0 -0
  64. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/attentionbasenet.py +0 -0
  65. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/attn_sleep.py +0 -0
  66. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/axon.py +0 -0
  67. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/barista.py +0 -0
  68. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/base.py +0 -0
  69. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/bendr.py +0 -0
  70. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/biot.py +0 -0
  71. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/brainbert.py +0 -0
  72. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/brainmodule.py +0 -0
  73. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/brainomni.py +0 -0
  74. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/brant.py +0 -0
  75. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/cbramod.py +0 -0
  76. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/codebrain.py +0 -0
  77. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/contrawr.py +0 -0
  78. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/csbrain.py +0 -0
  79. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/ctnet.py +0 -0
  80. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/dance.py +0 -0
  81. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/deep4.py +0 -0
  82. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/deepsleepnet.py +0 -0
  83. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/dgcnn.py +0 -0
  84. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/diver1.py +0 -0
  85. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/duin.py +0 -0
  86. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/eeg_clip.py +0 -0
  87. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/eegdino.py +0 -0
  88. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/eeginception_erp.py +0 -0
  89. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/eeginception_mi.py +0 -0
  90. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/eegitnet.py +0 -0
  91. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/eegminer.py +0 -0
  92. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/eegnet.py +0 -0
  93. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/eegnex.py +0 -0
  94. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/eegpt.py +0 -0
  95. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/eegsimpleconv.py +0 -0
  96. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/eegsym.py +0 -0
  97. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/eegtcnet.py +0 -0
  98. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/emg2qwerty.py +0 -0
  99. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/epint.py +0 -0
  100. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/fbcnet.py +0 -0
  101. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/fblightconvnet.py +0 -0
  102. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/fbmsnet.py +0 -0
  103. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/gcnsnet.py +0 -0
  104. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/guetschel2026.py +0 -0
  105. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/hybrid.py +0 -0
  106. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/ifnet.py +0 -0
  107. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/mapa.py +0 -0
  108. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/medformer.py +0 -0
  109. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/meta_neuromotor.py +0 -0
  110. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/mirepnet.py +0 -0
  111. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/mscformer.py +0 -0
  112. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/msvtnet.py +0 -0
  113. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/mvpformer.py +0 -0
  114. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/neuropose.py +0 -0
  115. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/neurorvq.py +0 -0
  116. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/neurorvq_tokenizer.py +0 -0
  117. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/patchedtransformer.py +0 -0
  118. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/popt.py +0 -0
  119. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/reve.py +0 -0
  120. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/sccnet.py +0 -0
  121. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/seizure_transformer.py +0 -0
  122. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/sensingdynamics.py +0 -0
  123. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/shallow_fbcsp.py +0 -0
  124. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/signal_jepa.py +0 -0
  125. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/sinc_shallow.py +0 -0
  126. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
  127. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  128. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/sleepfm.py +0 -0
  129. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/sparcnet.py +0 -0
  130. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/sstdpn.py +0 -0
  131. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/steegformer.py +0 -0
  132. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/summary.csv +0 -0
  133. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/syncnet.py +0 -0
  134. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/tcformer.py +0 -0
  135. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/tcn.py +0 -0
  136. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/tfm_tokenizer.py +0 -0
  137. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/tidnet.py +0 -0
  138. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/tmsanet.py +0 -0
  139. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/tsinception.py +0 -0
  140. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/usleep.py +0 -0
  141. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/vemg2pose.py +0 -0
  142. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/models/zuna.py +0 -0
  143. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/__init__.py +0 -0
  144. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/activation.py +0 -0
  145. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/attention.py +0 -0
  146. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/blocks.py +0 -0
  147. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/channels.py +0 -0
  148. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/convolution.py +0 -0
  149. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/dance_modules.py +0 -0
  150. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/filter.py +0 -0
  151. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/layers.py +0 -0
  152. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/linear.py +0 -0
  153. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/linear_attention.py +0 -0
  154. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/parametrization.py +0 -0
  155. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/quantization.py +0 -0
  156. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/stats.py +0 -0
  157. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/util.py +0 -0
  158. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/modules/wrapper.py +0 -0
  159. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/preprocessing/__init__.py +0 -0
  160. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
  161. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/preprocessing/mne_preprocess.py +0 -0
  162. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/preprocessing/preprocess.py +0 -0
  163. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/preprocessing/util.py +0 -0
  164. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/preprocessing/windowers.py +0 -0
  165. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/regressor.py +0 -0
  166. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/samplers/__init__.py +0 -0
  167. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/samplers/base.py +0 -0
  168. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/samplers/ssl.py +0 -0
  169. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/training/__init__.py +0 -0
  170. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/training/_trial_aggregation.py +0 -0
  171. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/training/callbacks.py +0 -0
  172. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/training/losses.py +0 -0
  173. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/training/scoring.py +0 -0
  174. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/visualization/__init__.py +0 -0
  175. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/visualization/activations.py +0 -0
  176. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/visualization/attribution.py +0 -0
  177. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/visualization/confusion_matrices.py +0 -0
  178. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/visualization/frequency.py +0 -0
  179. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/visualization/metrics.py +0 -0
  180. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/visualization/sanity.py +0 -0
  181. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode/visualization/topology.py +0 -0
  182. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode.egg-info/SOURCES.txt +0 -0
  183. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode.egg-info/dependency_links.txt +0 -0
  184. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode.egg-info/requires.txt +0 -0
  185. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/braindecode.egg-info/top_level.txt +0 -0
  186. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/Makefile +0 -0
  187. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/_templates/autosummary/class.rst +0 -0
  188. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  189. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/_templates/autosummary/function.rst +0 -0
  190. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  191. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/agent_docs.rst +0 -0
  192. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/api.rst +0 -0
  193. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/cite.rst +0 -0
  194. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/conf.py +0 -0
  195. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/help.rst +0 -0
  196. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/index.rst +0 -0
  197. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/install/install.rst +0 -0
  198. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/install/install_pip.rst +0 -0
  199. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/install/install_source.rst +0 -0
  200. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/models/categorization/attention.rst +0 -0
  201. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/models/categorization/channel.rst +0 -0
  202. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/models/categorization/convolution.rst +0 -0
  203. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/models/categorization/filterbank.rst +0 -0
  204. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/models/categorization/gnn.rst +0 -0
  205. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/models/categorization/interpretable.rst +0 -0
  206. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/models/categorization/lbm.rst +0 -0
  207. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/models/categorization/recurrent.rst +0 -0
  208. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/models/categorization/spd.rst +0 -0
  209. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/models/models.rst +0 -0
  210. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/models/models_categorization.rst +0 -0
  211. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/models/models_table.rst +0 -0
  212. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/models/models_visualization.rst +0 -0
  213. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/sg_execution_times.rst +0 -0
  214. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/user_guide/channel_strategies.rst +0 -0
  215. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/docs/user_guide/cropped_inference.rst +0 -0
  216. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/pyproject.toml +0 -0
  217. {braindecode-1.8.1.dev183052608 → braindecode-1.8.1.dev183240691}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.8.1.dev183052608
3
+ Version: 1.8.1.dev183240691
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>
@@ -0,0 +1,53 @@
1
+ import importlib
2
+ from typing import TYPE_CHECKING
3
+
4
+ from .version import __version__
5
+
6
+ if TYPE_CHECKING: # type checkers and IDEs see the classes; runtime uses __getattr__
7
+ from .classifier import EEGClassifier
8
+ from .regressor import EEGRegressor
9
+
10
+ __all__ = [
11
+ "__version__",
12
+ "EEGClassifier",
13
+ "EEGRegressor",
14
+ ]
15
+
16
+ # Subpackages reachable as ``braindecode.<name>`` after a bare ``import braindecode``.
17
+ _SUBMODULES = frozenset(
18
+ {
19
+ "augmentation",
20
+ "classifier",
21
+ "datasets",
22
+ "datautil",
23
+ "eegneuralnet",
24
+ "functional",
25
+ "models",
26
+ "modules",
27
+ "preprocessing",
28
+ "regressor",
29
+ "samplers",
30
+ "training",
31
+ "util",
32
+ "visualization",
33
+ }
34
+ )
35
+
36
+ if not TYPE_CHECKING: # hidden from checkers so misspelled names stay errors
37
+
38
+ def __getattr__(name):
39
+ # PEP 562: skorch, the datasets and the models load on first use.
40
+ if name == "EEGClassifier":
41
+ from .classifier import EEGClassifier
42
+
43
+ return EEGClassifier
44
+ if name == "EEGRegressor":
45
+ from .regressor import EEGRegressor
46
+
47
+ return EEGRegressor
48
+ if name in _SUBMODULES:
49
+ return importlib.import_module(f".{name}", __name__)
50
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
51
+
52
+ def __dir__():
53
+ return sorted(set(globals()) | set(__all__) | _SUBMODULES)
@@ -26,6 +26,7 @@ from itertools import chain
26
26
  from operator import attrgetter
27
27
  from pathlib import Path
28
28
  from typing import Any, Generic, Iterable, no_type_check
29
+ from uuid import uuid4
29
30
 
30
31
  import mne
31
32
  import mne.io
@@ -479,14 +480,14 @@ def _zarr_to_memmap(zarr_path, group_name):
479
480
  ``SIGBUS`` when workers page-faulted on the unlinked inode.
480
481
 
481
482
  Under ``N`` concurrent writers, every racer materialises the data
482
- into its own per-pid temp file and then tries to publish it; at
483
+ into its own per-call temp file and then tries to publish it; at
483
484
  most one ``os.link`` wins, and the losers silently ``unlink``
484
485
  their temp file in a ``finally`` block. The wasted I/O scales
485
486
  with the number of racers; for the workloads braindecode targets
486
487
  (a handful of concurrent workers per group) it is negligible.
487
488
 
488
489
  Crash recovery: if a writer dies mid-run the only debris is a
489
- ``<group>.<pid>.tmp.npy`` file. Such files are namespaced by pid
490
+ ``<group>.<uuid>.tmp.npy`` file. Such files are unique per call
490
491
  so they can never collide with a live writer, they are never
491
492
  read by the fast path, and they do not prevent subsequent
492
493
  callers from producing a correct result. Caches written by
@@ -504,7 +505,10 @@ def _zarr_to_memmap(zarr_path, group_name):
504
505
 
505
506
  cache_dir.mkdir(parents=True, exist_ok=True)
506
507
  arr = zarr.open(zarr_path, mode="r")[group_name]["data"]
507
- tmp_path = cache_dir / f"{group_name}.{os.getpid()}.tmp.npy"
508
+ # Unique per call, not per pid: threads of one process must not share it.
509
+ # Exclusive creation, not tempfile.mkstemp, which would make it 0600.
510
+ tmp_path = cache_dir / f"{group_name}.{uuid4().hex}.tmp.npy"
511
+ tmp_path.open("xb").close()
508
512
  try:
509
513
  # Write chunk-by-chunk to avoid materialising the whole zarr
510
514
  # array in RAM.
@@ -531,9 +535,9 @@ def _zarr_to_memmap(zarr_path, group_name):
531
535
  # canonical one; ours is discarded in the finally block.
532
536
  pass
533
537
  finally:
534
- # Always remove our private per-pid temp file. It is
535
- # namespaced by pid so this cannot clobber a concurrent
536
- # writer's in-progress tmp file.
538
+ # Always remove our private per-call temp file. Its name is
539
+ # unique per call so this cannot clobber a concurrent writer's
540
+ # in-progress tmp file.
537
541
  try:
538
542
  os.unlink(tmp_path)
539
543
  except FileNotFoundError:
@@ -0,0 +1,133 @@
1
+ """Some predefined network architectures for EEG decoding."""
2
+
3
+ import ast
4
+ import importlib
5
+ from typing import TYPE_CHECKING
6
+
7
+ _LAZY: dict[str, str] # public name -> submodule, read below from the imports
8
+
9
+ # A new model needs one import line here. It gives type checkers the class and,
10
+ # read back at runtime, the lazy name -> submodule map and ``__all__``; so these
11
+ # imports are used although no code names them.
12
+ # ruff: noqa: F401
13
+ if TYPE_CHECKING:
14
+ from .atcnet import ATCNet
15
+ from .attentionbasenet import AttentionBaseNet
16
+ from .attn_sleep import AttnSleep
17
+ from .axon import AXON
18
+ from .barista import BaRISTA
19
+ from .base import EEGModuleMixin
20
+ from .bendr import BENDR
21
+ from .biot import BIOT
22
+ from .brainbert import BrainBERT
23
+ from .brainmodule import BrainModule
24
+ from .brainomni import BrainOmni, BrainTokenizer
25
+ from .brant import Brant
26
+ from .cbramod import CBraMod
27
+ from .codebrain import CodeBrain
28
+ from .contrawr import ContraWR
29
+ from .csbrain import CSBrain
30
+ from .ctnet import CTNet
31
+ from .dance import DANCE
32
+ from .deep4 import Deep4Net
33
+ from .deepsleepnet import DeepSleepNet
34
+ from .dgcnn import DGCNN
35
+ from .diver1 import DIVER1
36
+ from .duin import DuIN
37
+ from .eeg_clip import EEGCLIP
38
+ from .eegconformer import EEGConformer
39
+ from .eegdino import EEGDINO
40
+ from .eeginception_erp import EEGInceptionERP
41
+ from .eeginception_mi import EEGInceptionMI
42
+ from .eegitnet import EEGITNet
43
+ from .eegminer import EEGMiner
44
+ from .eegnet import EEGNet
45
+ from .eegnex import EEGNeX
46
+ from .eegpt import EEGPT
47
+ from .eegsimpleconv import EEGSimpleConv
48
+ from .eegsym import EEGSym
49
+ from .eegtcnet import EEGTCNet
50
+ from .emg2qwerty import EMG2QwertyNet
51
+ from .epint import EpiNT
52
+ from .fbcnet import FBCNet
53
+ from .fblightconvnet import FBLightConvNet
54
+ from .fbmsnet import FBMSNet
55
+ from .gcnsnet import GCNsNet
56
+ from .guetschel2026 import Guetschel2026
57
+ from .hybrid import HybridNet
58
+ from .ifnet import IFNet
59
+ from .labram import Labram
60
+ from .luna import LUNA
61
+ from .mapa import MAPA
62
+ from .medformer import MEDFormer
63
+ from .meta_neuromotor import MetaNeuromotorHand
64
+ from .mirepnet import MIRepNet
65
+ from .mscformer import MSCFormer
66
+ from .msvtnet import MSVTNet
67
+ from .mvpformer import MVPFormer
68
+ from .neuropose import NeuroPose
69
+ from .neurorvq import NeuroRVQ
70
+ from .neurorvq_tokenizer import NeuroRVQTokenizer
71
+ from .patchedtransformer import PBT
72
+ from .popt import PopulationTransformer
73
+ from .reve import REVE
74
+ from .sccnet import SCCNet
75
+ from .seizure_transformer import SeizureTransformer
76
+ from .sensingdynamics import SensingDynamics
77
+ from .shallow_fbcsp import ShallowFBCSPNet
78
+ from .signal_jepa import (
79
+ SignalJEPA,
80
+ SignalJEPA_Contextual,
81
+ SignalJEPA_PostLocal,
82
+ SignalJEPA_PreLocal,
83
+ )
84
+ from .sinc_shallow import SincShallowNet
85
+ from .sleep_stager_blanco_2020 import SleepStagerBlanco2020
86
+ from .sleep_stager_chambon_2018 import SleepStagerChambon2018
87
+ from .sleepfm import SleepFM, SleepFMStager
88
+ from .sparcnet import SPARCNet
89
+ from .sstdpn import SSTDPN
90
+ from .steegformer import STEEGFormer
91
+ from .syncnet import SyncNet
92
+ from .tcformer import TCFormer
93
+ from .tcn import BDTCN, TCN
94
+ from .tfm_tokenizer import TFMTokenizer, TFMTokenizerOutput
95
+ from .tidnet import TIDNet
96
+ from .tmsanet import TMSANet
97
+ from .tsinception import TSception
98
+ from .usleep import USleep
99
+ from .util import (
100
+ _init_models_dict,
101
+ build_model_config,
102
+ extract_channel_locations_from_chs_info,
103
+ models_mandatory_parameters,
104
+ positions_from_chs_info,
105
+ )
106
+ from .vemg2pose import VEMG2Pose
107
+ from .zuna import ZUNA
108
+ else: # hidden from checkers so misspelled names stay errors
109
+
110
+ def _type_checking_imports():
111
+ # ponytail: needs this file's source, as get_summary_table needs summary.csv.
112
+ with open(__file__, "rb") as source:
113
+ tree = ast.parse(source.read())
114
+ block = next(node for node in tree.body if isinstance(node, ast.If))
115
+ return {alias.name: imp.module for imp in block.body for alias in imp.names}
116
+
117
+ # Each submodule is imported on first attribute access (PEP 562), so
118
+ # ``import braindecode`` does not load every model.
119
+ _LAZY = _type_checking_imports()
120
+ __all__ = list(_LAZY)
121
+
122
+ def __getattr__(name):
123
+ if name in _LAZY:
124
+ value = getattr(importlib.import_module(f".{_LAZY[name]}", __name__), name)
125
+ elif name in _LAZY.values():
126
+ value = importlib.import_module(f".{name}", __name__)
127
+ else:
128
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
129
+ globals()[name] = value
130
+ return value
131
+
132
+ def __dir__():
133
+ return sorted(set(globals()) | set(__all__))
@@ -12,8 +12,6 @@ from braindecode.models.base import EEGModuleMixin
12
12
  from braindecode.models.util import (
13
13
  SigArgName,
14
14
  _get_model_class,
15
- _init_models_dict,
16
- models_dict,
17
15
  models_mandatory_parameters,
18
16
  resolve_config_type,
19
17
  )
@@ -216,9 +214,6 @@ def make_model_config(
216
214
  # and define __all__ based on generated classes
217
215
  __all__ = ["make_model_config"]
218
216
 
219
- if not models_dict:
220
- _init_models_dict()
221
-
222
217
  models_configs: list[type[BaseBraindecodeModelConfig]] = []
223
218
  for model_name, req, _ in models_mandatory_parameters:
224
219
  model_cls = _get_model_class(model_name)
@@ -7,6 +7,7 @@ import torch
7
7
  import torch.nn.functional as F
8
8
  from einops.layers.torch import Rearrange
9
9
  from torch import Tensor, nn
10
+ from torch.utils.checkpoint import checkpoint
10
11
 
11
12
  from braindecode.models.base import EEGModuleMixin, _too_short_input_error
12
13
  from braindecode.modules import (
@@ -181,6 +182,15 @@ class EEGConformer(EEGModuleMixin, nn.Module):
181
182
  activation_transfor: nn.Module
182
183
  Activation function as parameter, applied at the FeedForwardBlock module
183
184
  inside the transformer. Default is nn.GeLU
185
+ activation_checkpointing : bool, default=False
186
+ Recompute the transformer blocks during backward (non-reentrant, RNG
187
+ preserved) to save training memory at the cost of extra compute.
188
+ Outputs and gradients were bit-identical to ``False`` in eager tests on
189
+ PyTorch 2.14.1 CPU. Only eager, gradient-enabled training is
190
+ checkpointed; the BatchNorm stem is never recomputed. There, hooks
191
+ (module or global) and buffers inside the transformer raise an error,
192
+ since recomputation would run them twice. Scripting, tracing, export
193
+ and compilation require ``False``.
184
194
 
185
195
  References
186
196
  ----------
@@ -193,6 +203,9 @@ class EEGConformer(EEGModuleMixin, nn.Module):
193
203
  https://github.com/eeyhsong/EEG-Conformer
194
204
  """
195
205
 
206
+ # Old full-object checkpoints restore state without calling __init__.
207
+ activation_checkpointing = False
208
+
196
209
  def __init__(
197
210
  self,
198
211
  n_outputs=None,
@@ -213,6 +226,8 @@ class EEGConformer(EEGModuleMixin, nn.Module):
213
226
  chs_info=None,
214
227
  input_window_seconds=None,
215
228
  sfreq=None,
229
+ *,
230
+ activation_checkpointing=False,
216
231
  ):
217
232
  super().__init__(
218
233
  n_outputs=n_outputs,
@@ -237,6 +252,7 @@ class EEGConformer(EEGModuleMixin, nn.Module):
237
252
  )
238
253
 
239
254
  self.return_features = return_features
255
+ self.activation_checkpointing = activation_checkpointing
240
256
 
241
257
  self.patch_embedding = _PatchEmbedding(
242
258
  n_filters_time=n_filters_time,
@@ -277,10 +293,24 @@ class EEGConformer(EEGModuleMixin, nn.Module):
277
293
 
278
294
  self.final_layer = nn.Linear(self.fc.hidden_channels, self.n_outputs)
279
295
 
296
+ def compile(self, *args, **kwargs):
297
+ # Reject before installing a native compiled call (including estimator
298
+ # ownership). Explicit disable=True still selects ordinary eager math.
299
+ if self.activation_checkpointing and not kwargs.get("disable", False):
300
+ raise RuntimeError("activation_checkpointing requires eager execution")
301
+ return super().compile(*args, **kwargs)
302
+
280
303
  def forward(self, x: Tensor) -> Tensor:
304
+ if self.activation_checkpointing:
305
+ if torch.jit.is_scripting():
306
+ raise RuntimeError("activation_checkpointing requires eager execution")
307
+ self._activation_checkpointing_requires_eager_execution()
281
308
  x = torch.unsqueeze(x, dim=1) # add one extra dimension
282
309
  x = self.patch_embedding(x)
283
- feature = self.transformer(x)
310
+ if self.activation_checkpointing and self.training and torch.is_grad_enabled():
311
+ feature = self._checkpoint_transformer(x)
312
+ else:
313
+ feature = self.transformer(x)
284
314
 
285
315
  if self.return_features:
286
316
  return feature
@@ -289,6 +319,41 @@ class EEGConformer(EEGModuleMixin, nn.Module):
289
319
  x = self.final_layer(x)
290
320
  return x
291
321
 
322
+ @torch.jit.unused
323
+ def _activation_checkpointing_requires_eager_execution(self):
324
+ if torch.jit.is_tracing() or torch.compiler.is_compiling():
325
+ raise RuntimeError("activation_checkpointing requires eager execution")
326
+
327
+ # torch._dynamo.forbid_in_graph without importing Dynamo: torch.compile
328
+ # fails here instead of falling back to eager checkpointing.
329
+ _activation_checkpointing_requires_eager_execution._dynamo_forbidden = True # type: ignore[attr-defined]
330
+
331
+ @torch.jit.unused
332
+ def _checkpoint_transformer(self, x: Tensor) -> Tensor:
333
+ from torch.nn.modules import module as global_hooks
334
+
335
+ hooks = (
336
+ "_forward_hooks",
337
+ "_forward_pre_hooks",
338
+ "_backward_hooks",
339
+ "_backward_pre_hooks",
340
+ )
341
+ if any(getattr(global_hooks, "_global" + name) for name in hooks):
342
+ raise RuntimeError(
343
+ "activation_checkpointing requires pure execution without global hooks"
344
+ )
345
+
346
+ # Recheck: users can attach hooks or replace children after construction.
347
+ for module in self.transformer.modules():
348
+ if module._buffers or any(getattr(module, name) for name in hooks):
349
+ raise RuntimeError(
350
+ "activation_checkpointing requires pure transformer blocks "
351
+ "without hooks or buffers"
352
+ )
353
+ for block in self.transformer:
354
+ x = checkpoint(block, x, use_reentrant=False, preserve_rng_state=True)
355
+ return x
356
+
292
357
  def get_fc_size(self):
293
358
  try:
294
359
  out = self.patch_embedding(torch.ones((1, 1, self.n_chans, self.n_times)))
@@ -1392,11 +1392,7 @@ class _Attention(nn.Module):
1392
1392
  if qkv_bias is not None:
1393
1393
  qkv = qkv + qkv_bias.to(qkv.dtype) # keep autocast dtype
1394
1394
  qkv = qkv.reshape(B, N, 3, self.num_heads, -1).permute(2, 0, 3, 1, 4)
1395
- q, k, v = (
1396
- qkv[0],
1397
- qkv[1],
1398
- qkv[2],
1399
- ) # make torchscript happy (cannot use tensor as tuple) (B, H, N, C)
1395
+ q, k, v = qkv.unbind(0) # (B, H, N, C); TorchScript cannot unpack qkv
1400
1396
  if self.q_norm is not None:
1401
1397
  q = self.q_norm(q).type_as(v)
1402
1398
  if self.k_norm is not None:
@@ -594,16 +594,15 @@ class _RotarySelfAttentionBlock(nn.Module):
594
594
  self.proj = nn.Linear(dim, dim)
595
595
  self.proj_drop = nn.Dropout(proj_drop)
596
596
 
597
- def _rotate_queries_or_keys(self, tensor: torch.Tensor) -> torch.Tensor:
598
- """Apply full-head RoPE without concatenating empty boundary views."""
597
+ def _rotary_tables(self, tensor: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
598
+ """Build RoPE tables for one forward; no cache, the frequencies may train."""
599
599
  seq_len = tensor.shape[-2]
600
600
  positions = torch.arange(seq_len, device=tensor.device, dtype=tensor.dtype)
601
601
  freqs = self.rotary_emb(positions)
602
602
 
603
603
  # Keep the full-head reshape (including its empty-input boundary).
604
604
  tensor.reshape(list(tensor.shape[:-1]) + [-1, 2])
605
- transformed = apply_rotary(tensor, freqs.cos(), freqs.sin())
606
- return transformed.to(tensor.dtype)
605
+ return freqs.cos(), freqs.sin()
607
606
 
608
607
  def forward(self, x: torch.Tensor) -> torch.Tensor:
609
608
  B, N, C = x.shape
@@ -615,8 +614,9 @@ class _RotarySelfAttentionBlock(nn.Module):
615
614
  # unbind, not qkv[0..2]: the backward of three selects writes three
616
615
  # zero-filled copies of the whole qkv tensor and sums them.
617
616
  q, k, v = qkv.unbind(0)
618
- q = self._rotate_queries_or_keys(q)
619
- k = self._rotate_queries_or_keys(k)
617
+ cos, sin = self._rotary_tables(q) # k has the shape of q
618
+ q = apply_rotary(q, cos, sin).to(q.dtype)
619
+ k = apply_rotary(k, cos, sin).to(k.dtype)
620
620
  attn = F.scaled_dot_product_attention(
621
621
  q,
622
622
  k,
@@ -5,6 +5,7 @@
5
5
  # License: BSD (3-clause)
6
6
  import inspect
7
7
  import math
8
+ import sys
8
9
  import warnings
9
10
  from collections.abc import Callable as CallableABC
10
11
  from copy import deepcopy
@@ -12,6 +13,7 @@ from functools import lru_cache, wraps
12
13
  from pathlib import Path
13
14
  from types import SimpleNamespace
14
15
  from typing import (
16
+ TYPE_CHECKING,
15
17
  Any,
16
18
  Callable,
17
19
  Dict,
@@ -26,10 +28,8 @@ from typing import (
26
28
 
27
29
  import mne
28
30
  import numpy as np
29
- import pandas as pd
30
31
  import torch # noqa: F401 # exposed so TorchScript can resolve ``torch`` through the BatchNorm-guard wrapper's __globals__
31
32
  from mne.io.constants import FIFF
32
- from sklearn.metrics import pairwise_distances_argmin
33
33
  from torch import nn
34
34
  from torchaudio.transforms import Resample
35
35
 
@@ -49,7 +49,27 @@ _KIND_TO_CH_TYPE = {
49
49
  INTRACRANIAL_CH_TYPES = frozenset({"seeg", "dbs", "ecog"})
50
50
 
51
51
 
52
- models_dict = {}
52
+ # Read through ``models_dict`` (module ``__getattr__`` below), which fills it on
53
+ # first access so importing braindecode does not import every model.
54
+ _models_dict: dict[str, Any] = {}
55
+ # Annotations only, for type checkers; the values come from ``__getattr__``.
56
+ models_dict: dict[str, Any]
57
+ _summary_table: "pd.DataFrame"
58
+
59
+ if TYPE_CHECKING:
60
+ import pandas as pd
61
+ else: # hidden from checkers so misspelled names stay errors
62
+
63
+ def __getattr__(name):
64
+ if name == "models_dict":
65
+ if not _models_dict:
66
+ _init_models_dict()
67
+ return _models_dict
68
+ if name == "_summary_table": # read summary.csv once, on first access
69
+ table = globals()[name] = get_summary_table()
70
+ return table
71
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
72
+
53
73
 
54
74
  # Resolve serialized classes by exact lookup, never by importing a config path.
55
75
  # Include public aliases and the defining paths emitted by get_config().
@@ -261,14 +281,18 @@ def resolve_type_kwargs(cls, kwargs):
261
281
 
262
282
 
263
283
  def _init_models_dict():
264
- import braindecode.models as models
284
+ from braindecode import models
285
+ from braindecode.models.base import EEGModuleMixin
265
286
 
266
- for m in inspect.getmembers(models, inspect.isclass):
267
- if (
268
- issubclass(m[1], models.base.EEGModuleMixin)
269
- and m[1] != models.base.EEGModuleMixin
270
- ):
271
- models_dict[m[0]] = m[1]
287
+ # Plain getattr over every public name: a model that fails to import raises here.
288
+ found = {}
289
+ for name in sorted(models._LAZY):
290
+ obj = getattr(models, name)
291
+ is_model = inspect.isclass(obj) and issubclass(obj, EEGModuleMixin)
292
+ if is_model and obj is not EEGModuleMixin:
293
+ found[name] = obj
294
+ # One update() publishes every entry at once, so no thread sees a partial dict.
295
+ _models_dict.update(found)
272
296
 
273
297
 
274
298
  def _get_model_class(model_name: str):
@@ -292,10 +316,9 @@ def _get_model_class(model_name: str):
292
316
  ValueError
293
317
  If ``model_name`` is not a registered model.
294
318
  """
295
- if not models_dict:
296
- _init_models_dict()
297
- if model_name in models_dict:
298
- return models_dict[model_name]
319
+ registry = sys.modules[__name__].models_dict # also honours a patched models_dict
320
+ if model_name in registry:
321
+ return registry[model_name]
299
322
  raise ValueError(f"Unknown model name {model_name!r}.")
300
323
 
301
324
 
@@ -897,6 +920,8 @@ def get_summary_table(dir_name=None):
897
920
 
898
921
  path = dir_path / "summary.csv"
899
922
 
923
+ import pandas as pd
924
+
900
925
  df = pd.read_csv(
901
926
  path,
902
927
  header=0,
@@ -1095,6 +1120,8 @@ def resolve_channel_indices(
1095
1120
  if not np.isfinite(norms).all() or np.any(norms <= 1e-7):
1096
1121
  return None
1097
1122
  directions = radial / norms
1123
+ from sklearn.metrics import pairwise_distances_argmin
1124
+
1098
1125
  nearest = pairwise_distances_argmin(
1099
1126
  directions[: len(locations)], directions[len(locations) :], metric=metric
1100
1127
  )
@@ -1274,6 +1301,3 @@ def channel_types_from_chs_info(
1274
1301
  else:
1275
1302
  types.append("unknown")
1276
1303
  return types
1277
-
1278
-
1279
- _summary_table = get_summary_table()
@@ -12,7 +12,6 @@ import h5py
12
12
  import mne
13
13
  import numpy as np
14
14
  import torch
15
- from sklearn.utils import check_random_state
16
15
  from torch import Tensor
17
16
 
18
17
 
@@ -299,6 +298,8 @@ def create_mne_dummy_raw(
299
298
  save_fname : dict | None
300
299
  Dictionary containing the name the raw data was saved to.
301
300
  """
301
+ from sklearn.utils import check_random_state
302
+
302
303
  random_state = check_random_state(random_state)
303
304
  data = random_state.rand(n_channels, n_times)
304
305
  ch_names = [f"ch{i}" for i in range(n_channels)]
@@ -0,0 +1 @@
1
+ __version__ = "1.8.1.dev183240691"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.8.1.dev183052608
3
+ Version: 1.8.1.dev183240691
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>
@@ -28,6 +28,39 @@ Current 1.8.1 (2026-08-31)
28
28
  Enhancements
29
29
  ============
30
30
 
31
+ - ``import braindecode`` and ``import braindecode.models`` no longer import
32
+ every model, the estimators, scikit-learn and pandas up front: the model
33
+ classes, :class:`braindecode.EEGClassifier`, :class:`~braindecode.EEGRegressor`,
34
+ the subpackages and ``models_dict`` load on first access (PEP 562 module
35
+ ``__getattr__``), with the same names, ``__all__`` and model registry. On
36
+ CPU with torch 2.14.1, ``import braindecode`` took 5 ms instead of 3.1 s and
37
+ ``from braindecode.models import EEGNet`` 1.6 s instead of 3.1 s. A new model
38
+ needs one import line, in the ``if TYPE_CHECKING:`` block of
39
+ ``braindecode/models/__init__.py``, as the new-model checklist says (by
40
+ `Bruno Aristimunha`_).
41
+ - :class:`braindecode.models.LUNA` reuses differentiable rotary tables within
42
+ each attention forward (no persistent cache); :class:`braindecode.models.Labram`
43
+ splits its fused qkv projection with ``unbind`` instead of three selects.
44
+ Parameters, checkpoint keys and numerical computations are preserved; LUNA
45
+ trainable-frequency gradients can differ by floating-point accumulation
46
+ rounding, and rotary-module hooks run once rather than twice per forward
47
+ (by `Bruno Aristimunha`_).
48
+ - :class:`braindecode.models.EEGConformer` takes the opt-in, keyword-only
49
+ ``activation_checkpointing=False``: non-reentrant activation checkpointing
50
+ recomputes pure transformer blocks during backward with RNG preservation.
51
+ Outputs, gradients and an optimizer step were bit-identical to checkpointing
52
+ off in eager tests on PyTorch 2.14.1 CPU; old pickled models still load.
53
+ Checkpointing requires eager execution; unsupported configurations are
54
+ explicitly rejected (see the parameter documentation). On an Intel Xeon
55
+ Gold 6230R CPU with four PyTorch/BLAS threads,
56
+ FP32, embedding dimension 64, eight heads, six layers and dropout, five paired
57
+ fresh processes at input shape ``[8, 22, 8192]`` measured 55.39% lower peak
58
+ process RSS (median paired ratio 0.446142) and 73.14% extra train-step time
59
+ (median paired ratio 1.731425) at equal batch. The largest passing integer
60
+ batch under a 4 GiB peak process RSS budget increased from 17 to 68 in a
61
+ fresh-process capacity search; this machine/runtime-qualified, one-run
62
+ boundary is a memory-capacity result, not an equal-batch speed improvement
63
+ (by `Bruno Aristimunha`_).
31
64
  - Add :func:`braindecode.training.iter_trial_predictions`,
32
65
  :func:`~braindecode.training.iter_trial_prediction_chunks` and
33
66
  :class:`~braindecode.training.TrialPredictionChunk` to stream cropped
@@ -524,6 +557,9 @@ Requirements
524
557
  Bug fixes
525
558
  ==========
526
559
 
560
+ - Zarr cache creation reserves a unique temporary file per call (exclusive
561
+ creation), so threads of one process no longer share one; permissions and
562
+ existing caches are unchanged (by `Bruno Aristimunha`_).
527
563
  - :class:`braindecode.training.PostEpochTrainScoring` restores the saved CPU
528
564
  Torch RNG state even when its reevaluation fails (by `Bruno Aristimunha`_).
529
565
  - :class:`braindecode.modules.FilterBankLayer`, and so :class:`braindecode.models.FBCNet`, :class:`braindecode.models.FBMSNet`, :class:`braindecode.models.FBLightConvNet` and :class:`braindecode.models.IFNet`, script again with PyTorch 2.15, where ``torch.jit.script`` failed inside :func:`torchaudio.functional.lfilter` ("Expression of type dots cannot be used in a type expression"). Eager filtering still calls torchaudio; the scripted graph runs the same operations as before, so outputs are unchanged (:gh:`1501` by `Bruno Aristimunha`_).
@@ -1,9 +0,0 @@
1
- from .classifier import EEGClassifier
2
- from .regressor import EEGRegressor
3
- from .version import __version__
4
-
5
- __all__ = [
6
- "__version__",
7
- "EEGClassifier",
8
- "EEGRegressor",
9
- ]