Braindecode 1.5.0.dev985__tar.gz → 1.5.0.dev989__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 (163) hide show
  1. {braindecode-1.5.0.dev985/braindecode.egg-info → braindecode-1.5.0.dev989}/PKG-INFO +1 -1
  2. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/__init__.py +0 -2
  3. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/signal_jepa.py +38 -446
  4. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/summary.csv +0 -1
  5. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/util.py +0 -5
  6. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/preprocessing/eegprep_preprocess.py +6 -51
  7. braindecode-1.5.0.dev989/braindecode/version.py +1 -0
  8. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989/braindecode.egg-info}/PKG-INFO +1 -1
  9. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode.egg-info/SOURCES.txt +0 -1
  10. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/api.rst +0 -3
  11. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/whats_new.rst +0 -12
  12. braindecode-1.5.0.dev985/braindecode/models/codebrain.py +0 -977
  13. braindecode-1.5.0.dev985/braindecode/version.py +0 -1
  14. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/LICENSE.txt +0 -0
  15. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/MANIFEST.in +0 -0
  16. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/NOTICE.txt +0 -0
  17. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/README.rst +0 -0
  18. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/__init__.py +0 -0
  19. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/augmentation/__init__.py +0 -0
  20. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/augmentation/base.py +0 -0
  21. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/augmentation/functional.py +0 -0
  22. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/augmentation/transforms.py +0 -0
  23. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/classifier.py +0 -0
  24. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/__init__.py +0 -0
  25. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/base.py +0 -0
  26. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/bbci.py +0 -0
  27. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/bcicomp.py +0 -0
  28. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/bids/__init__.py +0 -0
  29. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/bids/datasets.py +0 -0
  30. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/bids/format.py +0 -0
  31. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/bids/hub.py +0 -0
  32. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/bids/hub_format.py +0 -0
  33. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/bids/hub_io.py +0 -0
  34. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/bids/hub_validation.py +0 -0
  35. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/bids/iterable.py +0 -0
  36. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/chb_mit.py +0 -0
  37. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/mne.py +0 -0
  38. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/moabb.py +0 -0
  39. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/nmt.py +0 -0
  40. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/registry.py +0 -0
  41. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/siena.py +0 -0
  42. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  43. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/sleep_physionet.py +0 -0
  44. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/tuh.py +0 -0
  45. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/utils.py +0 -0
  46. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datasets/xy.py +0 -0
  47. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datautil/__init__.py +0 -0
  48. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datautil/channel_utils.py +0 -0
  49. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datautil/hub_formats.py +0 -0
  50. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datautil/serialization.py +0 -0
  51. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/datautil/util.py +0 -0
  52. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/eegneuralnet.py +0 -0
  53. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/functional/__init__.py +0 -0
  54. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/functional/functions.py +0 -0
  55. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/functional/initialization.py +0 -0
  56. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/atcnet.py +0 -0
  57. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/attentionbasenet.py +0 -0
  58. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/attn_sleep.py +0 -0
  59. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/base.py +0 -0
  60. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/bendr.py +0 -0
  61. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/biot.py +0 -0
  62. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/brainmodule.py +0 -0
  63. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/cbramod.py +0 -0
  64. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/config.py +0 -0
  65. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/contrawr.py +0 -0
  66. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/ctnet.py +0 -0
  67. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/deep4.py +0 -0
  68. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/deepsleepnet.py +0 -0
  69. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/dgcnn.py +0 -0
  70. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/eegconformer.py +0 -0
  71. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/eeginception_erp.py +0 -0
  72. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/eeginception_mi.py +0 -0
  73. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/eegitnet.py +0 -0
  74. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/eegminer.py +0 -0
  75. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/eegnet.py +0 -0
  76. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/eegnex.py +0 -0
  77. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/eegpt.py +0 -0
  78. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/eegsimpleconv.py +0 -0
  79. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/eegsym.py +0 -0
  80. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/eegtcnet.py +0 -0
  81. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/fbcnet.py +0 -0
  82. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/fblightconvnet.py +0 -0
  83. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/fbmsnet.py +0 -0
  84. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/hybrid.py +0 -0
  85. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/ifnet.py +0 -0
  86. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/labram.py +0 -0
  87. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/luna.py +0 -0
  88. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/medformer.py +0 -0
  89. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/msvtnet.py +0 -0
  90. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/patchedtransformer.py +0 -0
  91. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/reve.py +0 -0
  92. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/sccnet.py +0 -0
  93. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/shallow_fbcsp.py +0 -0
  94. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/sinc_shallow.py +0 -0
  95. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
  96. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  97. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/sparcnet.py +0 -0
  98. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/sstdpn.py +0 -0
  99. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/syncnet.py +0 -0
  100. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/tcn.py +0 -0
  101. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/tidnet.py +0 -0
  102. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/tsinception.py +0 -0
  103. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/models/usleep.py +0 -0
  104. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/modules/__init__.py +0 -0
  105. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/modules/activation.py +0 -0
  106. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/modules/attention.py +0 -0
  107. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/modules/blocks.py +0 -0
  108. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/modules/convolution.py +0 -0
  109. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/modules/filter.py +0 -0
  110. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/modules/layers.py +0 -0
  111. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/modules/linear.py +0 -0
  112. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/modules/parametrization.py +0 -0
  113. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/modules/stats.py +0 -0
  114. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/modules/util.py +0 -0
  115. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/modules/wrapper.py +0 -0
  116. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/preprocessing/__init__.py +0 -0
  117. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/preprocessing/mne_preprocess.py +0 -0
  118. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/preprocessing/preprocess.py +0 -0
  119. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/preprocessing/util.py +0 -0
  120. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/preprocessing/windowers.py +0 -0
  121. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/regressor.py +0 -0
  122. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/samplers/__init__.py +0 -0
  123. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/samplers/base.py +0 -0
  124. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/samplers/ssl.py +0 -0
  125. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/training/__init__.py +0 -0
  126. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/training/callbacks.py +0 -0
  127. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/training/losses.py +0 -0
  128. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/training/scoring.py +0 -0
  129. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/util.py +0 -0
  130. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/visualization/__init__.py +0 -0
  131. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/visualization/confusion_matrices.py +0 -0
  132. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode/visualization/gradients.py +0 -0
  133. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode.egg-info/dependency_links.txt +0 -0
  134. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode.egg-info/requires.txt +0 -0
  135. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/braindecode.egg-info/top_level.txt +0 -0
  136. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/Makefile +0 -0
  137. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/_templates/autosummary/class.rst +0 -0
  138. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  139. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/_templates/autosummary/function.rst +0 -0
  140. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  141. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/cite.rst +0 -0
  142. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/conf.py +0 -0
  143. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/help.rst +0 -0
  144. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/index.rst +0 -0
  145. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/install/install.rst +0 -0
  146. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/install/install_pip.rst +0 -0
  147. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/install/install_source.rst +0 -0
  148. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/models/categorization/attention.rst +0 -0
  149. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/models/categorization/channel.rst +0 -0
  150. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/models/categorization/convolution.rst +0 -0
  151. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/models/categorization/filterbank.rst +0 -0
  152. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/models/categorization/gnn.rst +0 -0
  153. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/models/categorization/interpretable.rst +0 -0
  154. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/models/categorization/lbm.rst +0 -0
  155. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/models/categorization/recurrent.rst +0 -0
  156. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/models/categorization/spd.rst +0 -0
  157. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/models/models.rst +0 -0
  158. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/models/models_categorization.rst +0 -0
  159. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/models/models_table.rst +0 -0
  160. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/models/models_visualization.rst +0 -0
  161. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/docs/sg_execution_times.rst +0 -0
  162. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/pyproject.toml +0 -0
  163. {braindecode-1.5.0.dev985 → braindecode-1.5.0.dev989}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.5.0.dev985
3
+ Version: 1.5.0.dev989
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>
@@ -8,7 +8,6 @@ from .bendr import BENDR
8
8
  from .biot import BIOT
9
9
  from .brainmodule import BrainModule
10
10
  from .cbramod import CBraMod
11
- from .codebrain import CodeBrain
12
11
  from .contrawr import ContraWR
13
12
  from .ctnet import CTNet
14
13
  from .deep4 import Deep4Net
@@ -73,7 +72,6 @@ __all__ = [
73
72
  "BIOT",
74
73
  "BENDR",
75
74
  "CBraMod",
76
- "CodeBrain",
77
75
  "ContraWR",
78
76
  "CTNet",
79
77
  "Deep4Net",
@@ -22,179 +22,12 @@ _DEFAULT_CONV_LAYER_SPEC = ( # downsampling: 128Hz -> 1Hz, receptive field 1.18
22
22
  (64, 2, 2),
23
23
  )
24
24
 
25
- # The 62 channels used to pre-train Signal-JEPA. Derived from
26
- # `moabb.datasets.Lee2019_SSVEP` subject 1 session '1' run '1train'
27
- # (the first 62 ch_names; the last 5 of the dataset's 67 channels are
28
- # 4 EMG + 1 stim). Positions are from MNE's `standard_1005` montage.
29
- # Names and ORDER MUST match the _ChannelEmbedding row order of the
30
- # published HuggingFace checkpoint `braindecode/signal-jepa`.
31
- _PRETRAIN_CHS_INFO: list[dict] = [
32
- {"ch_name": "Fp1", "loc": [-0.0294367, 0.0839171, -0.00699]},
33
- {"ch_name": "Fp2", "loc": [0.0298723, 0.0848959, -0.00708]},
34
- {"ch_name": "F7", "loc": [-0.0702629, 0.0424743, -0.01142]},
35
- {"ch_name": "F3", "loc": [-0.0502438, 0.0531112, 0.042192]},
36
- {"ch_name": "Fz", "loc": [0.0003122, 0.058512, 0.066462]},
37
- {"ch_name": "F4", "loc": [0.0518362, 0.0543048, 0.040814]},
38
- {"ch_name": "F8", "loc": [0.0730431, 0.0444217, -0.012]},
39
- {"ch_name": "FC5", "loc": [-0.0772149, 0.0186433, 0.02446]},
40
- {"ch_name": "FC1", "loc": [-0.0340619, 0.0260111, 0.079987]},
41
- {"ch_name": "FC2", "loc": [0.0347841, 0.0264379, 0.078808]},
42
- {"ch_name": "FC6", "loc": [0.0795341, 0.0199357, 0.024438]},
43
- {"ch_name": "T7", "loc": [-0.0841611, -0.0160187, -0.009346]},
44
- {"ch_name": "C3", "loc": [-0.0653581, -0.0116317, 0.064358]},
45
- {"ch_name": "Cz", "loc": [0.0004009, -0.009167, 0.100244]},
46
- {"ch_name": "C4", "loc": [0.0671179, -0.0109003, 0.06358]},
47
- {"ch_name": "T8", "loc": [0.0850799, -0.0150203, -0.00949]},
48
- {"ch_name": "TP9", "loc": [-0.0856192, -0.0465147, -0.045707]},
49
- {"ch_name": "CP5", "loc": [-0.0795922, -0.0465507, 0.030949]},
50
- {"ch_name": "CP1", "loc": [-0.0355131, -0.0472919, 0.091315]},
51
- {"ch_name": "CP2", "loc": [0.0383838, -0.0470731, 0.090695]},
52
- {"ch_name": "CP6", "loc": [0.0833218, -0.0461013, 0.031206]},
53
- {"ch_name": "TP10", "loc": [0.0861618, -0.0470353, -0.045869]},
54
- {"ch_name": "P7", "loc": [-0.0724343, -0.0734527, -0.002487]},
55
- {"ch_name": "P3", "loc": [-0.0530073, -0.0787878, 0.05594]},
56
- {"ch_name": "Pz", "loc": [0.0003247, -0.081115, 0.082615]},
57
- {"ch_name": "P4", "loc": [0.0556667, -0.0785602, 0.056561]},
58
- {"ch_name": "P8", "loc": [0.0730557, -0.0730683, -0.00254]},
59
- {"ch_name": "PO9", "loc": [-0.0549104, -0.0980448, -0.035465]},
60
- {"ch_name": "O1", "loc": [-0.0294134, -0.112449, 0.008839]},
61
- {"ch_name": "Oz", "loc": [0.0001076, -0.114892, 0.014657]},
62
- {"ch_name": "O2", "loc": [0.0298426, -0.112156, 0.0088]},
63
- {"ch_name": "PO10", "loc": [0.0549876, -0.0980911, -0.035541]},
64
- {"ch_name": "FC3", "loc": [-0.0601819, 0.0227162, 0.055544]},
65
- {"ch_name": "FC4", "loc": [0.0622931, 0.0237228, 0.05563]},
66
- {"ch_name": "C5", "loc": [-0.0802801, -0.0137597, 0.02916]},
67
- {"ch_name": "C1", "loc": [-0.036158, -0.0099839, 0.089752]},
68
- {"ch_name": "C2", "loc": [0.037672, -0.0096241, 0.088412]},
69
- {"ch_name": "C6", "loc": [0.0834559, -0.0127763, 0.029208]},
70
- {"ch_name": "CP3", "loc": [-0.0635562, -0.0470088, 0.065624]},
71
- {"ch_name": "CPz", "loc": [0.0003858, -0.047318, 0.099432]},
72
- {"ch_name": "CP4", "loc": [0.0666118, -0.0466372, 0.06558]},
73
- {"ch_name": "P1", "loc": [-0.0286203, -0.0805249, 0.075436]},
74
- {"ch_name": "P2", "loc": [0.0319197, -0.0804871, 0.076716]},
75
- {"ch_name": "POz", "loc": [0.0002156, -0.102178, 0.050608]},
76
- {"ch_name": "FT9", "loc": [-0.0840759, 0.0145673, -0.050429]},
77
- {"ch_name": "FTT9h", "loc": [-0.084125, -0.0018467, -0.029794]},
78
- {"ch_name": "TTP7h", "loc": [-0.0855651, -0.0306287, 0.011153]},
79
- {"ch_name": "TP7", "loc": [-0.0848302, -0.0460217, -0.007056]},
80
- {"ch_name": "TPP9h", "loc": [-0.0781602, -0.0607567, -0.023824]},
81
- {"ch_name": "FT10", "loc": [0.0841131, 0.0143647, -0.050538]},
82
- {"ch_name": "FTT10h", "loc": [0.084123, -0.0018083, -0.029638]},
83
- {"ch_name": "TPP8h", "loc": [0.0785198, -0.0604323, 0.012902]},
84
- {"ch_name": "TP8", "loc": [0.0855488, -0.0455453, -0.00713]},
85
- {"ch_name": "TPP10h", "loc": [0.0789027, -0.0609553, -0.023805]},
86
- {"ch_name": "F9", "loc": [-0.0701019, 0.0416523, -0.049952]},
87
- {"ch_name": "F10", "loc": [0.0721141, 0.0420667, -0.050452]},
88
- {"ch_name": "AF7", "loc": [-0.0548397, 0.0685722, -0.01059]},
89
- {"ch_name": "AF3", "loc": [-0.0337007, 0.0768371, 0.021227]},
90
- {"ch_name": "AF4", "loc": [0.0357123, 0.0777259, 0.021956]},
91
- {"ch_name": "AF8", "loc": [0.0557433, 0.0696568, -0.010755]},
92
- {"ch_name": "PO3", "loc": [-0.0365114, -0.1008529, 0.037167]},
93
- {"ch_name": "PO4", "loc": [0.0367816, -0.1008491, 0.036397]},
94
- ]
95
-
96
-
97
- def _resolve_channel_embedding_config(
98
- channel_embedding: str,
99
- chs_info: list[dict] | None,
100
- ) -> tuple[list[dict], list[list[float] | None], torch.LongTensor]:
101
- """Resolve the construction parameters for ``_ChannelEmbedding``.
102
-
103
- Parameters
104
- ----------
105
- channel_embedding : {"scratch", "pretrain_aligned"}
106
- How to initialize ``_ChannelEmbedding``. See
107
- ``SignalJEPA`` docstring.
108
- chs_info : list of dict | None
109
- User-supplied channel information. Each element must be a
110
- mapping with at least the keys ``"ch_name"`` and ``"loc"``.
111
-
112
- Returns
113
- -------
114
- effective_chs_info : list of dict
115
- The ``chs_info`` that ``EEGModuleMixin`` should see. Equal to
116
- ``chs_info`` when provided, else ``_PRETRAIN_CHS_INFO``.
117
- channel_locations : list of (list of float or None)
118
- Locations used to initialize ``_ChannelEmbedding``. Length
119
- equals ``num_embeddings`` (N in ``'scratch'`` mode, 62 in
120
- ``'pretrain_aligned'`` mode).
121
- ch_idxs : torch.LongTensor, shape ``(len(effective_chs_info),)``
122
- Mapping from the user channel order to embedding indices.
123
-
124
- Raises
125
- ------
126
- ValueError
127
- If ``channel_embedding`` is not recognized, if
128
- ``channel_embedding='scratch'`` is combined with
129
- ``chs_info=None``, or if ``channel_embedding='pretrain_aligned'``
130
- is combined with a ``chs_info`` that contains a channel name
131
- absent from ``_PRETRAIN_CHS_INFO`` (case-insensitive match).
132
- """
133
- if channel_embedding not in ("scratch", "pretrain_aligned"):
134
- raise ValueError(
135
- "channel_embedding must be 'scratch' or 'pretrain_aligned', "
136
- f"got {channel_embedding!r}"
137
- )
138
-
139
- if channel_embedding == "scratch":
140
- if chs_info is None:
141
- raise ValueError("chs_info is required when channel_embedding='scratch'")
142
- effective_chs_info = list(chs_info)
143
- channel_locations = [ch["loc"] for ch in effective_chs_info]
144
- ch_idxs = torch.arange(len(effective_chs_info), dtype=torch.long)
145
- return effective_chs_info, channel_locations, ch_idxs
146
-
147
- # channel_embedding == "pretrain_aligned"
148
- pretrain_name_to_idx = {
149
- ch["ch_name"].lower(): i for i, ch in enumerate(_PRETRAIN_CHS_INFO)
150
- }
151
- channel_locations = [ch["loc"] for ch in _PRETRAIN_CHS_INFO]
152
-
153
- if chs_info is None:
154
- effective_chs_info = [dict(ch) for ch in _PRETRAIN_CHS_INFO]
155
- ch_idxs = torch.arange(len(_PRETRAIN_CHS_INFO), dtype=torch.long)
156
- return effective_chs_info, channel_locations, ch_idxs
157
-
158
- missing = [
159
- ch["ch_name"]
160
- for ch in chs_info
161
- if ch["ch_name"].lower() not in pretrain_name_to_idx
162
- ]
163
- if missing:
164
- raise ValueError(
165
- f"Channel(s) {missing} not in the Signal-JEPA pre-training set. "
166
- "To load pretrained weights while keeping these channels, use:\n"
167
- " channel_embedding='scratch'\n"
168
- " checkpoint 'braindecode/signal-jepa_without-chans'\n"
169
- " strict=False # on load_state_dict / from_pretrained\n"
170
- "The pretrained channel embedding weights will not be loaded."
171
- )
172
-
173
- effective_chs_info = list(chs_info)
174
- ch_idxs = torch.tensor(
175
- [pretrain_name_to_idx[ch["ch_name"].lower()] for ch in chs_info],
176
- dtype=torch.long,
177
- )
178
- return effective_chs_info, channel_locations, ch_idxs
179
-
180
25
 
181
26
  class _BaseSignalJEPA(EEGModuleMixin, nn.Module):
182
27
  r"""Base class for the SignalJEPA models
183
28
 
184
29
  Parameters
185
30
  ----------
186
- channel_embedding : {"scratch", "pretrain_aligned"}, default ``"scratch"``
187
- How to initialize the :class:`_ChannelEmbedding` table.
188
-
189
- * ``"scratch"``: table has ``len(chs_info)`` rows, initialized from
190
- user locations. ``chs_info`` is required.
191
- * ``"pretrain_aligned"``: table has 62 rows, initialized from the
192
- pre-training locations. If ``chs_info`` is provided, every channel
193
- name must match one in the pre-training set (case-insensitive);
194
- ``forward`` will then expect input with as many channels as
195
- ``chs_info`` has. If ``chs_info=None``, the model runs on the
196
- full 62 channels in the pre-training order.
197
-
198
31
  feature_encoder__conv_layers_spec: list of tuple
199
32
  tuples have shape ``(dim, k, stride)`` where:
200
33
 
@@ -266,32 +99,19 @@ class _BaseSignalJEPA(EEGModuleMixin, nn.Module):
266
99
  transformer__num_decoder_layers: int = 4,
267
100
  transformer__nhead: int = 8,
268
101
  # other
269
- channel_embedding: str = "scratch",
270
102
  _init_feature_encoder: bool,
271
103
  _init_transformer: bool,
272
104
  ):
273
- # Resolve channel embedding config before calling super().__init__
274
- if _init_transformer:
275
- effective_chs_info, channel_locations, ch_idxs = (
276
- _resolve_channel_embedding_config(channel_embedding, chs_info)
277
- )
278
- else:
279
- effective_chs_info = chs_info
280
- channel_locations = None
281
- ch_idxs = None
282
-
283
105
  super().__init__(
284
106
  n_outputs=n_outputs,
285
107
  n_chans=n_chans,
286
- chs_info=effective_chs_info,
108
+ chs_info=chs_info,
287
109
  n_times=n_times,
288
110
  input_window_seconds=input_window_seconds,
289
111
  sfreq=sfreq,
290
112
  )
291
113
  del n_outputs, n_chans, chs_info, n_times, input_window_seconds, sfreq
292
114
 
293
- self._channel_embedding = channel_embedding
294
-
295
115
  self.feature_encoder = None
296
116
  self.pos_encoder = None
297
117
  self.transformer = None
@@ -306,13 +126,11 @@ class _BaseSignalJEPA(EEGModuleMixin, nn.Module):
306
126
  )
307
127
 
308
128
  if _init_transformer:
309
- assert channel_locations is not None # narrowing for type checker
310
- assert ch_idxs is not None
129
+ ch_locs = [ch["loc"] for ch in self.chs_info] # type: ignore
311
130
  self.pos_encoder = _PosEncoder(
312
131
  spat_dim=pos_encoder__spat_dim,
313
132
  time_dim=pos_encoder__time_dim,
314
- channel_locations=channel_locations,
315
- ch_idxs=ch_idxs,
133
+ ch_locs=ch_locs,
316
134
  sfreq_features=pos_encoder__sfreq_features,
317
135
  spat_kwargs=pos_encoder__spat_kwargs,
318
136
  )
@@ -343,74 +161,6 @@ class SignalJEPA(_BaseSignalJEPA):
343
161
 
344
162
  .. versionadded:: 0.9
345
163
 
346
- .. rubric:: Pretrained Weights
347
-
348
- Two checkpoint variants are published on HuggingFace:
349
-
350
- - ``braindecode/signal-jepa``: full encoder + pre-trained channel embedding
351
- table (62 rows, one per pre-training channel). Use when your channel
352
- names are a subset of the pre-training set (``channel_embedding='pretrain_aligned'``).
353
- - ``braindecode/signal-jepa_without-chans``: same encoder, channel
354
- embedding weights stripped. Use when your channel set differs from
355
- pre-training; the table is freshly initialized from your channel
356
- locations (``channel_embedding='scratch'``, the default).
357
-
358
- .. important::
359
- **Pre-trained Weights Available**
360
-
361
- .. code-block:: python
362
-
363
- from braindecode.models import SignalJEPA
364
-
365
- # Load encoder + pre-trained channel embeddings (62 channels):
366
- model = SignalJEPA.from_pretrained("braindecode/signal-jepa")
367
-
368
- # Select a subset of the 62 pre-training channels:
369
- model = SignalJEPA.from_pretrained(
370
- "braindecode/signal-jepa",
371
- chs_info=[{"ch_name": "Fp1", "loc": [...]}, {"ch_name": "Cz", "loc": [...]}],
372
- )
373
-
374
- # Arbitrary channel set (channel embedding re-initialized from your locs):
375
- model = SignalJEPA.from_pretrained(
376
- "braindecode/signal-jepa_without-chans",
377
- chs_info=[{"ch_name": "A", "loc": [...]}, ...],
378
- strict=False,
379
- )
380
-
381
- To push your own trained model to the Hub:
382
-
383
- .. code-block:: python
384
-
385
- model.push_to_hub(
386
- repo_id="username/my-sjepa-model",
387
- commit_message="Upload trained SignalJEPA model",
388
- )
389
-
390
- Requires installing ``braindecode[hub]`` for Hub integration.
391
-
392
- .. rubric:: Usage
393
-
394
- .. code-block:: python
395
-
396
- from braindecode.models import SignalJEPA
397
-
398
- model = SignalJEPA(
399
- chs_info=[{"ch_name": "Fp1", "loc": [...]}, ...],
400
- input_window_seconds=16.0,
401
- sfreq=128,
402
- )
403
-
404
- # Forward: (batch, n_chans, n_times) -> (batch, n_chans * n_patches, emb_dim)
405
- features = model(eeg_data)
406
-
407
- .. warning::
408
-
409
- Pre-trained at **128 Hz** on EEG bandpass-filtered between
410
- **0.5 and 40 Hz** and rescaled by a factor of :math:`10^{6}`
411
- (volts to microvolts). Apply the same preprocessing to your
412
- data to match the pre-training distribution.
413
-
414
164
  References
415
165
  ----------
416
166
  .. [1] Guetschel, P., Moreau, T., & Tangermann, M. (2024).
@@ -445,8 +195,6 @@ class SignalJEPA(_BaseSignalJEPA):
445
195
  transformer__num_encoder_layers: int = 8,
446
196
  transformer__num_decoder_layers: int = 4,
447
197
  transformer__nhead: int = 8,
448
- # other
449
- channel_embedding: str = "scratch",
450
198
  ):
451
199
  super().__init__(
452
200
  n_outputs=n_outputs,
@@ -468,16 +216,15 @@ class SignalJEPA(_BaseSignalJEPA):
468
216
  transformer__num_encoder_layers=transformer__num_encoder_layers,
469
217
  transformer__num_decoder_layers=transformer__num_decoder_layers,
470
218
  transformer__nhead=transformer__nhead,
471
- channel_embedding=channel_embedding,
472
219
  _init_feature_encoder=True,
473
220
  _init_transformer=True,
474
221
  )
475
222
  del n_outputs, n_chans, chs_info, n_times, input_window_seconds, sfreq
476
223
  self.final_layer = nn.Identity()
477
224
 
478
- def forward(self, X, return_features=False): # type: ignore
225
+ def forward(self, X, ch_idxs: torch.Tensor | None = None, return_features=False): # type: ignore
479
226
  local_features = self.feature_encoder(X) # type: ignore
480
- pos_encoding = self.pos_encoder(local_features) # type: ignore
227
+ pos_encoding = self.pos_encoder(local_features, ch_idxs=ch_idxs) # type: ignore
481
228
  local_features += pos_encoding # type: ignore
482
229
  contextual_features = self.transformer.encoder(local_features) # type: ignore
483
230
  if return_features:
@@ -500,67 +247,6 @@ class SignalJEPA_Contextual(_BaseSignalJEPA):
500
247
 
501
248
  .. versionadded:: 0.9
502
249
 
503
- .. rubric:: Pretrained Weights
504
-
505
- Loads the pre-trained SSL encoder (feature encoder + transformer +
506
- channel embedding) from the shared checkpoints. Two hub IDs are
507
- available:
508
-
509
- - ``braindecode/signal-jepa``: with pre-trained channel embeddings
510
- (62 channels, ``channel_embedding='pretrain_aligned'``).
511
- - ``braindecode/signal-jepa_without-chans``: without channel embeddings.
512
- The embedding table is re-initialized from your channel locations
513
- (``channel_embedding='scratch'``, the default).
514
-
515
- .. important::
516
- **Pre-trained Weights Available**
517
-
518
- .. code-block:: python
519
-
520
- from braindecode.models import SignalJEPA_Contextual
521
-
522
- # Use pre-trained channel embeddings (subset of the 62 channels):
523
- model = SignalJEPA_Contextual.from_pretrained(
524
- "braindecode/signal-jepa",
525
- n_times=2048, # required: the SSL checkpoint is n_times-agnostic
526
- n_outputs=4,
527
- strict=False, # classifier head is not in the SSL checkpoint
528
- )
529
-
530
- # Arbitrary channel set:
531
- model = SignalJEPA_Contextual.from_pretrained(
532
- "braindecode/signal-jepa_without-chans",
533
- chs_info=[{"ch_name": "A", "loc": [...]}, ...],
534
- n_times=2048,
535
- n_outputs=4,
536
- strict=False,
537
- )
538
-
539
- Requires installing ``braindecode[hub]`` for Hub integration.
540
-
541
- .. rubric:: Usage
542
-
543
- .. code-block:: python
544
-
545
- from braindecode.models import SignalJEPA_Contextual
546
-
547
- model = SignalJEPA_Contextual(
548
- chs_info=[{"ch_name": "Fp1", "loc": [...]}, ...],
549
- input_window_seconds=16.0,
550
- sfreq=128,
551
- n_outputs=4, # e.g., 4-class classification
552
- )
553
-
554
- # Forward: (batch, n_chans, n_times) -> (batch, n_outputs)
555
- output = model(eeg_data)
556
-
557
- .. warning::
558
-
559
- Pre-trained at **128 Hz** on EEG bandpass-filtered between
560
- **0.5 and 40 Hz** and rescaled by a factor of :math:`10^{6}`
561
- (volts to microvolts). Apply the same preprocessing to your
562
- data to match the pre-training distribution.
563
-
564
250
  Parameters
565
251
  ----------
566
252
  n_spat_filters : int
@@ -602,7 +288,6 @@ class SignalJEPA_Contextual(_BaseSignalJEPA):
602
288
  transformer__num_decoder_layers: int = 4,
603
289
  transformer__nhead: int = 8,
604
290
  # other
605
- channel_embedding: str = "scratch",
606
291
  _init_feature_encoder: bool = True,
607
292
  _init_transformer: bool = True,
608
293
  ):
@@ -626,7 +311,6 @@ class SignalJEPA_Contextual(_BaseSignalJEPA):
626
311
  transformer__num_encoder_layers=transformer__num_encoder_layers,
627
312
  transformer__num_decoder_layers=transformer__num_decoder_layers,
628
313
  transformer__nhead=transformer__nhead,
629
- channel_embedding=channel_embedding,
630
314
  _init_feature_encoder=_init_feature_encoder,
631
315
  _init_transformer=_init_transformer,
632
316
  )
@@ -651,9 +335,9 @@ class SignalJEPA_Contextual(_BaseSignalJEPA):
651
335
  n_spat_filters=self._clf_n_spat_filters,
652
336
  )
653
337
 
654
- def forward(self, X, return_features=False): # type: ignore
338
+ def forward(self, X, ch_idxs: torch.Tensor | None = None, return_features=False): # type: ignore
655
339
  local_features = self.feature_encoder(X) # type: ignore
656
- pos_encoding = self.pos_encoder(local_features) # type: ignore
340
+ pos_encoding = self.pos_encoder(local_features, ch_idxs=ch_idxs) # type: ignore
657
341
  local_features += pos_encoding # type: ignore
658
342
  contextual_features = self.transformer.encoder(local_features) # type: ignore
659
343
  if return_features:
@@ -734,14 +418,9 @@ class SignalJEPA_Contextual(_BaseSignalJEPA):
734
418
  new_model.pos_encoder = deepcopy(pos_encoder)
735
419
  new_model.transformer = deepcopy(transformer)
736
420
 
737
- new_model._channel_embedding = model._channel_embedding
738
- if chs_info is not None and model._channel_embedding == "pretrain_aligned":
739
- _, _, new_ch_idxs = _resolve_channel_embedding_config(
740
- "pretrain_aligned", chs_info
741
- )
742
- new_model.pos_encoder.register_buffer(
743
- "default_ch_idxs", new_ch_idxs.to(torch.long), persistent=False
744
- )
421
+ if chs_info is not None:
422
+ ch_names = [ch["ch_name"] for ch in chs_info]
423
+ new_model.pos_encoder.set_fixed_ch_names(ch_names)
745
424
 
746
425
  return new_model
747
426
 
@@ -760,54 +439,6 @@ class SignalJEPA_PostLocal(_BaseSignalJEPA):
760
439
 
761
440
  .. versionadded:: 0.9
762
441
 
763
- .. rubric:: Pretrained Weights
764
-
765
- Only the feature encoder weights are reused from the shared
766
- SSL checkpoints. This model has no channel embedding nor transformer,
767
- so ``strict=False`` is required at load time to skip the unused keys.
768
- Either hub variant works; the ``_without-chans`` one is slightly
769
- smaller.
770
-
771
- .. important::
772
- **Pre-trained Weights Available**
773
-
774
- .. code-block:: python
775
-
776
- from braindecode.models import SignalJEPA_PostLocal
777
-
778
- model = SignalJEPA_PostLocal.from_pretrained(
779
- "braindecode/signal-jepa_without-chans",
780
- n_chans=22,
781
- input_window_seconds=16.0,
782
- n_outputs=4,
783
- strict=False,
784
- )
785
-
786
- Requires installing ``braindecode[hub]`` for Hub integration.
787
-
788
- .. rubric:: Usage
789
-
790
- .. code-block:: python
791
-
792
- from braindecode.models import SignalJEPA_PostLocal
793
-
794
- model = SignalJEPA_PostLocal(
795
- n_chans=22,
796
- input_window_seconds=16.0,
797
- sfreq=128,
798
- n_outputs=4, # e.g., 4-class classification
799
- )
800
-
801
- # Forward: (batch, n_chans, n_times) -> (batch, n_outputs)
802
- output = model(eeg_data)
803
-
804
- .. warning::
805
-
806
- Pre-trained at **128 Hz** on EEG bandpass-filtered between
807
- **0.5 and 40 Hz** and rescaled by a factor of :math:`10^{6}`
808
- (volts to microvolts). Apply the same preprocessing to your
809
- data to match the pre-training distribution.
810
-
811
442
  Parameters
812
443
  ----------
813
444
  n_spat_filters : int
@@ -976,62 +607,32 @@ class SignalJEPA_PreLocal(_BaseSignalJEPA):
976
607
 
977
608
  .. versionadded:: 0.9
978
609
 
979
- .. rubric:: Pretrained Weights
980
-
981
- Only the feature encoder weights are reused from the shared
982
- SSL checkpoints. This model has no channel embedding nor transformer,
983
- so ``strict=False`` is required at load time to skip the unused keys.
984
- Either hub variant works; the ``_without-chans`` one is slightly
985
- smaller.
986
-
987
610
  .. important::
988
611
  **Pre-trained Weights Available**
989
612
 
613
+ This model has pre-trained weights available on the Hugging Face Hub.
614
+ You can load them using:
615
+
990
616
  .. code-block:: python
991
617
 
992
618
  from braindecode.models import SignalJEPA_PreLocal
993
619
 
620
+ # Load pre-trained model from Hugging Face Hub
994
621
  model = SignalJEPA_PreLocal.from_pretrained(
995
- "braindecode/signal-jepa_without-chans",
996
- n_chans=22,
997
- input_window_seconds=16.0,
998
- n_outputs=4,
999
- strict=False,
622
+ "braindecode/SignalJEPA-PreLocal-pretrained"
1000
623
  )
1001
624
 
1002
625
  To push your own trained model to the Hub:
1003
626
 
1004
627
  .. code-block:: python
1005
628
 
629
+ # After training your model
1006
630
  model.push_to_hub(
1007
631
  repo_id="username/my-sjepa-model",
1008
632
  commit_message="Upload trained SignalJEPA model",
1009
633
  )
1010
634
 
1011
- Requires installing ``braindecode[hub]`` for Hub integration.
1012
-
1013
- .. rubric:: Usage
1014
-
1015
- .. code-block:: python
1016
-
1017
- from braindecode.models import SignalJEPA_PreLocal
1018
-
1019
- model = SignalJEPA_PreLocal(
1020
- n_chans=22,
1021
- input_window_seconds=16.0,
1022
- sfreq=128,
1023
- n_outputs=4, # e.g., 4-class classification
1024
- )
1025
-
1026
- # Forward: (batch, n_chans, n_times) -> (batch, n_outputs)
1027
- output = model(eeg_data)
1028
-
1029
- .. warning::
1030
-
1031
- Pre-trained at **128 Hz** on EEG bandpass-filtered between
1032
- **0.5 and 40 Hz** and rescaled by a factor of :math:`10^{6}`
1033
- (volts to microvolts). Apply the same preprocessing to your
1034
- data to match the pre-training distribution.
635
+ Requires installing ``braindecode[hug]`` for Hub integration.
1035
636
 
1036
637
  Parameters
1037
638
  ----------
@@ -1334,7 +935,11 @@ class _ChannelEmbedding(nn.Embedding):
1334
935
  self.coordinate_ranges = [
1335
936
  (min(coords), max(coords))
1336
937
  for coords in zip(
1337
- *[loc[:3] for loc in channel_locations if loc is not None]
938
+ *[
939
+ loc[3:6] if len(loc) == 12 else loc
940
+ for loc in channel_locations
941
+ if loc is not None
942
+ ]
1338
943
  )
1339
944
  ]
1340
945
  channel_mins, channel_maxs = zip(*self.coordinate_ranges)
@@ -1380,14 +985,8 @@ class _PosEncoder(nn.Module):
1380
985
  i.e. the EEG channel.
1381
986
  time_dim: int
1382
987
  Number of dimensions to use to encode the temporal position of the patch.
1383
- channel_locations: list of (list of float or None)
1384
- List of the n-dimensional locations of each entry in the channel
1385
- embedding table. Length equals the number of embedding rows
1386
- (N for ``'scratch'`` mode, 62 for ``'pretrain_aligned'`` mode).
1387
- ch_idxs: torch.LongTensor, shape ``(n_chans,)``
1388
- Default mapping from the model's channel order to rows of the
1389
- channel embedding table. Stored as a non-persistent buffer
1390
- (device-aware but excluded from ``state_dict``).
988
+ ch_locs: list of list of float or 2d array
989
+ List of the n-dimensions locations of the EEG channels.
1391
990
  sfreq_features: float
1392
991
  The "downsampled" sampling frequency returned by the feature encoder.
1393
992
  spat_kwargs: dict
@@ -1401,8 +1000,7 @@ class _PosEncoder(nn.Module):
1401
1000
  self,
1402
1001
  spat_dim: int,
1403
1002
  time_dim: int,
1404
- channel_locations: list[list[float] | None],
1405
- ch_idxs: torch.LongTensor,
1003
+ ch_locs,
1406
1004
  sfreq_features: float,
1407
1005
  spat_kwargs: dict | None = None,
1408
1006
  max_seconds: float = 600.0, # 10 minutes
@@ -1415,17 +1013,9 @@ class _PosEncoder(nn.Module):
1415
1013
 
1416
1014
  # Positional encoder for the spatial dimension:
1417
1015
  self.pos_encoder_spat = _ChannelEmbedding(
1418
- channel_locations, spat_dim, **spat_kwargs
1016
+ ch_locs, spat_dim, **spat_kwargs
1419
1017
  ) # (batch_size, n_channels, spat_dim)
1420
1018
 
1421
- # Default channel index mapping. Registered as a non-persistent
1422
- # buffer so it follows .to(device) but is NOT saved to state_dict.
1423
- # The mapping is fully determined by chs_info + channel_embedding
1424
- # at __init__, so persisting it would duplicate config.json.
1425
- self.register_buffer(
1426
- "default_ch_idxs", ch_idxs.to(torch.long), persistent=False
1427
- )
1428
-
1429
1019
  # Pre-computed tensor for positional encoding on the time dimension:
1430
1020
  self.encoding_time = torch.zeros(0, dtype=torch.float32, requires_grad=False)
1431
1021
 
@@ -1443,22 +1033,24 @@ class _PosEncoder(nn.Module):
1443
1033
  """
1444
1034
  Parameters
1445
1035
  ----------
1446
- local_features : (batch_size, n_chans * n_times_out, emb_dim)
1447
- ch_idxs : (batch_size, n_chans) | None
1448
- Indices of the channels into the embedding table. When ``None``,
1449
- ``self.default_ch_idxs`` (shape ``(n_chans,)``) is broadcast
1450
- across the batch.
1036
+ * local_features: (batch_size, n_chans * n_times_out, emb_dim)
1037
+ * ch_idxs: (batch_size, n_chans) | None
1038
+ Indices of the channels to use in the ``ch_names`` list passed
1039
+ as argument plus one. Index 0 is reserved for an unknown channel.
1451
1040
 
1452
1041
  Returns
1453
1042
  -------
1454
- pos_encoding : (batch_size, n_chans * n_times_out, emb_dim)
1455
- The first ``spat_dim`` dimensions encode the channel positional
1456
- encoding; the following ``time_dim`` dimensions encode the
1457
- temporal positional encoding.
1043
+ pos_encoding: (batch_size, n_chans * n_times_out, emb_dim)
1044
+ The first ``spat_dim`` dimensions encode the channels positional encoding
1045
+ and the following ``time_dim`` dimensions encode the temporal positional encoding.
1458
1046
  """
1459
1047
  batch_size, n_chans_times, emb_dim = local_features.shape
1460
1048
  if ch_idxs is None:
1461
- ch_idxs = self.default_ch_idxs[None, :].expand(batch_size, -1)
1049
+ ch_idxs = torch.arange(
1050
+ 0,
1051
+ self.pos_encoder_spat.num_embeddings,
1052
+ device=local_features.device,
1053
+ ).repeat(batch_size, 1)
1462
1054
 
1463
1055
  batch_size_chs, n_chans = ch_idxs.shape
1464
1056
  assert emb_dim >= self.spat_dim + self.time_dim