Braindecode 1.5.0.dev902__tar.gz → 1.5.0.dev982__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 (162) hide show
  1. {braindecode-1.5.0.dev902/braindecode.egg-info → braindecode-1.5.0.dev982}/PKG-INFO +1 -1
  2. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/base.py +19 -80
  3. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/attentionbasenet.py +2 -3
  4. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/syncnet.py +13 -17
  5. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/tsinception.py +1 -1
  6. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/modules/attention.py +16 -45
  7. braindecode-1.5.0.dev982/braindecode/version.py +1 -0
  8. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982/braindecode.egg-info}/PKG-INFO +1 -1
  9. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/install/install.rst +1 -1
  10. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/whats_new.rst +2 -29
  11. braindecode-1.5.0.dev902/braindecode/version.py +0 -1
  12. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/LICENSE.txt +0 -0
  13. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/MANIFEST.in +0 -0
  14. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/NOTICE.txt +0 -0
  15. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/README.rst +0 -0
  16. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/__init__.py +0 -0
  17. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/augmentation/__init__.py +0 -0
  18. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/augmentation/base.py +0 -0
  19. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/augmentation/functional.py +0 -0
  20. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/augmentation/transforms.py +0 -0
  21. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/classifier.py +0 -0
  22. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/__init__.py +0 -0
  23. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/bbci.py +0 -0
  24. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/bcicomp.py +0 -0
  25. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/bids/__init__.py +0 -0
  26. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/bids/datasets.py +0 -0
  27. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/bids/format.py +0 -0
  28. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/bids/hub.py +0 -0
  29. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/bids/hub_format.py +0 -0
  30. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/bids/hub_io.py +0 -0
  31. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/bids/hub_validation.py +0 -0
  32. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/bids/iterable.py +0 -0
  33. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/chb_mit.py +0 -0
  34. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/mne.py +0 -0
  35. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/moabb.py +0 -0
  36. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/nmt.py +0 -0
  37. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/registry.py +0 -0
  38. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/siena.py +0 -0
  39. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  40. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/sleep_physionet.py +0 -0
  41. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/tuh.py +0 -0
  42. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/utils.py +0 -0
  43. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datasets/xy.py +0 -0
  44. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datautil/__init__.py +0 -0
  45. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datautil/channel_utils.py +0 -0
  46. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datautil/hub_formats.py +0 -0
  47. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datautil/serialization.py +0 -0
  48. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/datautil/util.py +0 -0
  49. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/eegneuralnet.py +0 -0
  50. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/functional/__init__.py +0 -0
  51. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/functional/functions.py +0 -0
  52. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/functional/initialization.py +0 -0
  53. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/__init__.py +0 -0
  54. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/atcnet.py +0 -0
  55. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/attn_sleep.py +0 -0
  56. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/base.py +0 -0
  57. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/bendr.py +0 -0
  58. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/biot.py +0 -0
  59. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/brainmodule.py +0 -0
  60. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/cbramod.py +0 -0
  61. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/config.py +0 -0
  62. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/contrawr.py +0 -0
  63. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/ctnet.py +0 -0
  64. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/deep4.py +0 -0
  65. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/deepsleepnet.py +0 -0
  66. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/dgcnn.py +0 -0
  67. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/eegconformer.py +0 -0
  68. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/eeginception_erp.py +0 -0
  69. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/eeginception_mi.py +0 -0
  70. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/eegitnet.py +0 -0
  71. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/eegminer.py +0 -0
  72. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/eegnet.py +0 -0
  73. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/eegnex.py +0 -0
  74. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/eegpt.py +0 -0
  75. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/eegsimpleconv.py +0 -0
  76. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/eegsym.py +0 -0
  77. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/eegtcnet.py +0 -0
  78. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/fbcnet.py +0 -0
  79. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/fblightconvnet.py +0 -0
  80. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/fbmsnet.py +0 -0
  81. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/hybrid.py +0 -0
  82. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/ifnet.py +0 -0
  83. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/labram.py +0 -0
  84. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/luna.py +0 -0
  85. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/medformer.py +0 -0
  86. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/msvtnet.py +0 -0
  87. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/patchedtransformer.py +0 -0
  88. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/reve.py +0 -0
  89. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/sccnet.py +0 -0
  90. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/shallow_fbcsp.py +0 -0
  91. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/signal_jepa.py +0 -0
  92. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/sinc_shallow.py +0 -0
  93. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
  94. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  95. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/sparcnet.py +0 -0
  96. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/sstdpn.py +0 -0
  97. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/summary.csv +0 -0
  98. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/tcn.py +0 -0
  99. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/tidnet.py +0 -0
  100. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/usleep.py +0 -0
  101. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/models/util.py +0 -0
  102. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/modules/__init__.py +0 -0
  103. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/modules/activation.py +0 -0
  104. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/modules/blocks.py +0 -0
  105. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/modules/convolution.py +0 -0
  106. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/modules/filter.py +0 -0
  107. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/modules/layers.py +0 -0
  108. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/modules/linear.py +0 -0
  109. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/modules/parametrization.py +0 -0
  110. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/modules/stats.py +0 -0
  111. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/modules/util.py +0 -0
  112. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/modules/wrapper.py +0 -0
  113. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/preprocessing/__init__.py +0 -0
  114. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
  115. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/preprocessing/mne_preprocess.py +0 -0
  116. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/preprocessing/preprocess.py +0 -0
  117. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/preprocessing/util.py +0 -0
  118. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/preprocessing/windowers.py +0 -0
  119. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/regressor.py +0 -0
  120. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/samplers/__init__.py +0 -0
  121. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/samplers/base.py +0 -0
  122. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/samplers/ssl.py +0 -0
  123. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/training/__init__.py +0 -0
  124. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/training/callbacks.py +0 -0
  125. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/training/losses.py +0 -0
  126. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/training/scoring.py +0 -0
  127. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/util.py +0 -0
  128. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/visualization/__init__.py +0 -0
  129. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/visualization/confusion_matrices.py +0 -0
  130. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode/visualization/gradients.py +0 -0
  131. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode.egg-info/SOURCES.txt +0 -0
  132. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode.egg-info/dependency_links.txt +0 -0
  133. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode.egg-info/requires.txt +0 -0
  134. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/braindecode.egg-info/top_level.txt +0 -0
  135. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/Makefile +0 -0
  136. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/_templates/autosummary/class.rst +0 -0
  137. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  138. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/_templates/autosummary/function.rst +0 -0
  139. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  140. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/api.rst +0 -0
  141. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/cite.rst +0 -0
  142. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/conf.py +0 -0
  143. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/help.rst +0 -0
  144. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/index.rst +0 -0
  145. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/install/install_pip.rst +0 -0
  146. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/install/install_source.rst +0 -0
  147. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/models/categorization/attention.rst +0 -0
  148. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/models/categorization/channel.rst +0 -0
  149. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/models/categorization/convolution.rst +0 -0
  150. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/models/categorization/filterbank.rst +0 -0
  151. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/models/categorization/gnn.rst +0 -0
  152. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/models/categorization/interpretable.rst +0 -0
  153. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/models/categorization/lbm.rst +0 -0
  154. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/models/categorization/recurrent.rst +0 -0
  155. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/models/categorization/spd.rst +0 -0
  156. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/models/models.rst +0 -0
  157. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/models/models_categorization.rst +0 -0
  158. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/models/models_table.rst +0 -0
  159. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/models/models_visualization.rst +0 -0
  160. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/docs/sg_execution_times.rst +0 -0
  161. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/pyproject.toml +0 -0
  162. {braindecode-1.5.0.dev902 → braindecode-1.5.0.dev982}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.5.0.dev902
3
+ Version: 1.5.0.dev982
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>
@@ -298,95 +298,34 @@ def _build_windowed_repr(
298
298
 
299
299
 
300
300
  def _zarr_to_memmap(zarr_path, group_name):
301
- """Materialise a zarr array as a float64 ``.npy`` memmap, race-free.
302
-
303
- Decompress the ``group_name`` array inside ``zarr_path`` into a
304
- float64 ``.npy`` file inside a sibling ``.<zarr>_memmap/`` cache
305
- directory and return the path to that file. The dtype is float64
306
- because MNE objects wrap the memmap zero-copy and MNE requires
307
- float64 internally. Callers open the result with
308
- ``np.load(path, mmap_mode='c')`` so preprocessing writes land in
309
- anonymous copy-on-write pages and never mutate the on-disk file.
310
-
311
- Concurrency contract
312
- --------------------
313
- Safe to call from any number of threads or processes concurrently
314
- on the same ``(zarr_path, group_name)``, on local POSIX, NFSv3,
315
- Lustre and SMB. The published ``.npy`` file is **created exactly
316
- once and never replaced**: subsequent callers either hit the
317
- already-materialised file on the fast path or lose the
318
- publication race and discard their own copy.
319
-
320
- The atomic publication step is ``os.link``, not ``rename``.
321
- ``os.link(tmp, dst)`` either creates ``dst`` pointing at ``tmp``'s
322
- inode or fails with :class:`FileExistsError` when ``dst`` already
323
- exists — the "create only if absent" primitive we need, available
324
- on every POSIX filesystem. ``rename`` was the wrong primitive:
325
- it atomically *replaces* its destination, which unlinks the inode
326
- that concurrent readers may already have ``mmap``'d. On NFSv3
327
- that produced ``.nfsXXXX`` silly-rename files and intermittent
328
- ``SIGBUS`` when workers page-faulted on the unlinked inode.
329
-
330
- Under ``N`` concurrent writers, every racer materialises the data
331
- into its own per-pid temp file and then tries to publish it; at
332
- most one ``os.link`` wins, and the losers silently ``unlink``
333
- their temp file in a ``finally`` block. The wasted I/O scales
334
- with the number of racers; for the workloads braindecode targets
335
- (a handful of concurrent workers per group) it is negligible.
336
-
337
- Crash recovery: if a writer dies mid-run the only debris is a
338
- ``<group>.<pid>.tmp.npy`` file. Such files are namespaced by pid
339
- so they can never collide with a live writer, they are never
340
- read by the fast path, and they do not prevent subsequent
341
- callers from producing a correct result. Caches written by
342
- earlier braindecode versions remain valid: the fast path only
343
- requires ``<group>.npy`` to exist.
301
+ """Decompress a zarr array to a float64 ``.npy`` memmap (one-time, atomic).
302
+
303
+ Saved as float64 so MNE objects can wrap the memmap zero-copy
304
+ (MNE requires float64 internally). Copy-on-write mode (``'c'``)
305
+ means preprocessing writes go to RAM, the file stays untouched.
344
306
  """
345
307
  zarr_p = Path(zarr_path)
346
308
  cache_dir = zarr_p.parent / f".{zarr_p.name}_memmap"
347
309
  npy_path = cache_dir / f"{group_name}.npy"
348
310
 
349
- # Fast path: the file is already fully materialised. A single
350
- # stat() is all the steady-state workload pays.
351
- if npy_path.exists():
352
- return npy_path
353
-
354
- cache_dir.mkdir(parents=True, exist_ok=True)
355
- arr = zarr.open(zarr_path, mode="r")[group_name]["data"]
356
- tmp_path = cache_dir / f"{group_name}.{os.getpid()}.tmp.npy"
357
- try:
358
- # Write chunk-by-chunk to avoid materialising the whole zarr
359
- # array in RAM.
311
+ if not npy_path.exists():
312
+ arr = zarr.open(zarr_path, mode="r")[group_name]["data"]
313
+ cache_dir.mkdir(parents=True, exist_ok=True)
314
+ tmp_path = cache_dir / f"{group_name}.{os.getpid()}.tmp.npy"
315
+ # Write chunk-by-chunk to avoid materializing the full array in RAM
360
316
  mm = np.lib.format.open_memmap(
361
317
  tmp_path, mode="w+", dtype=np.float64, shape=arr.shape
362
318
  )
319
+ chunk0 = arr.chunks[0] if hasattr(arr, "chunks") else arr.shape[0]
320
+ for start in range(0, arr.shape[0], chunk0):
321
+ end = min(start + chunk0, arr.shape[0])
322
+ mm[start:end] = np.asarray(arr[start:end], dtype=np.float64)
323
+ mm.flush()
324
+ del mm
363
325
  try:
364
- chunk0 = arr.chunks[0] if hasattr(arr, "chunks") else arr.shape[0]
365
- for start in range(0, arr.shape[0], chunk0):
366
- end = min(start + chunk0, arr.shape[0])
367
- mm[start:end] = np.asarray(arr[start:end], dtype=np.float64)
368
- mm.flush()
369
- finally:
370
- del mm
371
-
372
- # Atomic publication. ``os.link`` never replaces an existing
373
- # destination, so the published inode is immutable for the
374
- # lifetime of the cache directory. Concurrent readers never
375
- # see their mmap'd inode vanish from under them.
376
- try:
377
- os.link(tmp_path, npy_path)
378
- except FileExistsError:
379
- # Another writer beat us to it. Their file is the
380
- # canonical one; ours is discarded in the finally block.
381
- pass
382
- finally:
383
- # Always remove our private per-pid temp file. It is
384
- # namespaced by pid so this cannot clobber a concurrent
385
- # writer's in-progress tmp file.
386
- try:
387
- os.unlink(tmp_path)
388
- except FileNotFoundError:
389
- pass
326
+ tmp_path.rename(npy_path)
327
+ except OSError:
328
+ tmp_path.unlink(missing_ok=True)
390
329
 
391
330
  return npy_path
392
331
 
@@ -1,8 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- # Authors: Sarthak Tayal <sarthaktayal2@gmail.com>
4
- #
5
- # License: BSD (3-clause)
6
3
  import math
7
4
 
8
5
  from einops.layers.torch import Rearrange
@@ -278,6 +275,8 @@ class AttentionBaseNet(EEGModuleMixin, nn.Module):
278
275
  activation: type[nn.Module] = nn.ELU,
279
276
  extra_params: bool = False,
280
277
  ):
278
+ super(AttentionBaseNet, self).__init__()
279
+
281
280
  super().__init__(
282
281
  n_outputs=n_outputs,
283
282
  n_chans=n_chans,
@@ -1,7 +1,3 @@
1
- # Authors: Sarthak Tayal <sarthaktayal2@gmail.com>
2
- #
3
- # License: BSD (3-clause)
4
-
5
1
  import torch
6
2
  import torch.nn as nn
7
3
  import torch.nn.functional as F
@@ -55,11 +51,11 @@ class SyncNet(EEGModuleMixin, nn.Module):
55
51
  The initialization range for omega parameters using uniform
56
52
  distribution. Default is (0, 1).
57
53
  beta_init_values : tuple of float, optional
58
- The initialization range for beta (decay) parameters using uniform
59
- distribution. Default is (0, 0.05).
54
+ The initialization range for beta parameters using uniform
55
+ distribution. Default is (0, 1). Default is (0, 0.05).
60
56
  phase_init_values : tuple of float, optional
61
- The initialization mean and standard deviation for phase
62
- parameters using normal distribution. Default is (0, 0.05).
57
+ The initialization range for phase parameters using `normal`
58
+ distribution. Default is (0, 1). Default is (0, 0.05).
63
59
 
64
60
 
65
61
  Notes
@@ -150,12 +146,12 @@ class SyncNet(EEGModuleMixin, nn.Module):
150
146
  # Phase Shift
151
147
  self.phi_ini = nn.Parameter(
152
148
  torch.FloatTensor(1, 1, self.n_chans, self.num_filters).normal_(
153
- self.phase_init_values[0], self.phase_init_values[1]
149
+ self.beta_init_values[0], self.beta_init_values[1]
154
150
  )
155
151
  )
156
152
  self.beta = nn.Parameter(
157
153
  torch.FloatTensor(1, 1, 1, self.num_filters).uniform_(
158
- self.beta_init_values[0], self.beta_init_values[1]
154
+ self.phase_init_values[0], self.phase_init_values[1]
159
155
  )
160
156
  )
161
157
 
@@ -189,21 +185,21 @@ class SyncNet(EEGModuleMixin, nn.Module):
189
185
  # Output: (batch_size, n_chans, 1, n_times)
190
186
 
191
187
  # Compute the oscillatory component
192
- # Shape: (1, filter_width, n_chans, num_filters)
193
188
  W_osc = self.amplitude * torch.cos(self.t * self.omega + self.phi_ini)
189
+ # W_osc is (1, filter_width, n_chans, 1)
194
190
 
195
191
  # Compute the decay component
196
- # Shape: (1, filter_width, 1, num_filters)
197
- t_squared = torch.pow(self.t, 2)
198
- t_squared_beta = t_squared * self.beta
192
+ t_squared = torch.pow(self.t, 2) # Shape: (filter_width,)
193
+ t_squared_beta = t_squared * self.beta # Shape: (filter_width, num_filters)
199
194
  W_decay = torch.exp(-t_squared_beta)
195
+ # W_osc is (1, filter_width, 1, 1)
200
196
 
201
197
  # Combine oscillatory and decay components
202
- # Shape: (1, filter_width, n_chans, num_filters)
198
+ # W shape: (1, n_chans, num_filters, filter_width)
203
199
  W = W_osc * W_decay
200
+ # W shape will be: (1, filter_width, n_chans, 1)
204
201
 
205
- # Permute to conv2d weight shape (out_channels, in_channels, kH, kW)
206
- W = W.permute(3, 2, 0, 1).contiguous()
202
+ W = W.view(self.num_filters, self.n_chans, 1, self.filter_width)
207
203
 
208
204
  # Apply convolution
209
205
  x_padded = self.pad_input(x.float())
@@ -1,4 +1,4 @@
1
- # Authors: Bruno Aristimunha <b.aristimunha@gmail.com>
1
+ # Authors: Bruno Aristimunha <b.aristimunha>
2
2
  #
3
3
  # License: BSD (3-clause)
4
4
 
@@ -837,18 +837,6 @@ class CATLite(nn.Module):
837
837
  class MultiHeadAttention(nn.Module):
838
838
  """Multi-head self-attention block.
839
839
 
840
- Uses ``F.scaled_dot_product_attention`` for optimized attention
841
- kernels (flash-attention on CUDA, memory-efficient on other devices).
842
-
843
- Parameters
844
- ----------
845
- emb_size : int
846
- The embedding dimension.
847
- num_heads : int
848
- Number of attention heads. Must evenly divide ``emb_size``.
849
- dropout : float, optional
850
- Dropout probability applied to attention weights. Default: 0.0.
851
-
852
840
  Examples
853
841
  --------
854
842
  >>> import torch
@@ -860,57 +848,40 @@ class MultiHeadAttention(nn.Module):
860
848
  torch.Size([2, 10, 32])
861
849
  """
862
850
 
863
- def __init__(self, emb_size, num_heads, dropout=0.0):
851
+ def __init__(self, emb_size, num_heads, dropout):
864
852
  super().__init__()
865
- if emb_size % num_heads != 0:
866
- raise ValueError(
867
- f"emb_size ({emb_size}) must be divisible by num_heads ({num_heads})."
868
- )
869
853
  self.emb_size = emb_size
870
854
  self.num_heads = num_heads
871
- self.head_dim = emb_size // num_heads
872
855
  self.keys = nn.Linear(emb_size, emb_size)
873
856
  self.queries = nn.Linear(emb_size, emb_size)
874
857
  self.values = nn.Linear(emb_size, emb_size)
875
- self.att_drop = dropout
858
+ self.att_drop = nn.Dropout(dropout)
876
859
  self.projection = nn.Linear(emb_size, emb_size)
877
860
 
878
861
  self.rearrange_stack = Rearrange(
879
- "batch seq (heads head_dim) -> batch heads seq head_dim",
880
- heads=num_heads,
862
+ "b n (h d) -> b h n d",
863
+ h=num_heads,
881
864
  )
882
865
  self.rearrange_unstack = Rearrange(
883
- "batch heads seq head_dim -> batch seq (heads head_dim)",
866
+ "b h n d -> b n (h d)",
884
867
  )
885
868
 
886
869
  def forward(self, x: Tensor, mask: Optional[Tensor] = None) -> Tensor:
887
- """Forward pass.
888
-
889
- Parameters
890
- ----------
891
- x : Tensor
892
- Input tensor of shape ``(batch, seq, emb_size)``.
893
- mask : Tensor, optional
894
- Attention mask following PyTorch SDPA convention: for boolean
895
- masks ``True`` means **ignore** that position; for float
896
- masks the values are **added** to attention scores before
897
- softmax.
898
- """
899
870
  queries = self.rearrange_stack(self.queries(x))
900
871
  keys = self.rearrange_stack(self.keys(x))
901
872
  values = self.rearrange_stack(self.values(x))
902
-
903
- dp = self.att_drop if self.training else 0.0
904
- out = F.scaled_dot_product_attention(
905
- queries,
906
- keys,
907
- values,
908
- attn_mask=mask,
909
- dropout_p=dp,
910
- )
911
-
873
+ energy = torch.einsum("bhqd, bhkd -> bhqk", queries, keys)
874
+ if mask is not None:
875
+ fill_value = float("-inf")
876
+ energy = energy.masked_fill(~mask, fill_value)
877
+
878
+ scaling = self.emb_size ** (1 / 2)
879
+ att = F.softmax(energy / scaling, dim=-1)
880
+ att = self.att_drop(att)
881
+ out = torch.einsum("bhal, bhlv -> bhav ", att, values)
912
882
  out = self.rearrange_unstack(out)
913
- return self.projection(out)
883
+ out = self.projection(out)
884
+ return out
914
885
 
915
886
 
916
887
  class CrissCrossTransformerEncoderLayer(nn.Module):
@@ -0,0 +1 @@
1
+ __version__ = "1.5.0.dev982"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.5.0.dev902
3
+ Version: 1.5.0.dev982
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>
@@ -4,7 +4,7 @@
4
4
  Installation
5
5
  ##############
6
6
 
7
- Braindecode is written in Python 3, specifically for version 3.11 or above.
7
+ Braindecode is written in Python 3, specifically for version 3.10 or above.
8
8
 
9
9
  The package is distributed via Python package index (`PyPI <braindecode-pypi_>`_), and
10
10
  you can access the source code via `Github <braindecode-github_>`_ repository.
@@ -28,19 +28,10 @@ Current 1.5.0 (GitHub)
28
28
  Enhancements
29
29
  ============
30
30
 
31
- - Use ``F.scaled_dot_product_attention`` in :class:`braindecode.modules.MultiHeadAttention`,
32
- enabling optimized attention kernels (flash-attention on CUDA,
33
- memory-efficient backends on other devices).
34
- By `Léo Burgund`_ and `Bruno Aristimunha`_.
35
- (:gh:`902`)
36
-
37
31
  API and behavior changes
38
32
  ========================
39
33
 
40
- - :class:`braindecode.modules.MultiHeadAttention` now follows PyTorch's SDPA mask
41
- convention: boolean masks use ``True`` to **ignore** a position (previously
42
- ``True`` meant keep). The scaling factor is now ``1/sqrt(head_dim)`` instead of
43
- ``1/sqrt(emb_size)``. (:gh:`902`)
34
+ - None yet
44
35
 
45
36
  Requirements
46
37
  ============
@@ -50,25 +41,7 @@ Requirements
50
41
  Bug fixes
51
42
  ==========
52
43
 
53
- - Fix :class:`braindecode.models.SyncNet` swapped parameter initialization where
54
- ``phi_ini`` (phase shift) was using ``beta_init_values`` and ``beta`` (decay) was
55
- using ``phase_init_values``, replaced incorrect ``.view()`` reshape with ``.permute()``
56
- for proper conv2d filter weight layout, and fixed duplicate default values in docstring
57
- (by `Sarthak Tayal`_)
58
- - Fix :class:`braindecode.models.AttentionBaseNet` redundant
59
- ``super().__init__()`` call that ran the parent ``nn.Module.__init__`` twice
60
- (by `Sarthak Tayal`_)
61
- - Fix incomplete author email in :class:`braindecode.models.TSception` header
62
- (by `Sarthak Tayal`_)
63
- - Fix a time-of-check-time-of-use race in
64
- :func:`braindecode.datasets.base._zarr_to_memmap` that caused
65
- concurrent workers to repeatedly ``rename``-replace the published
66
- ``.npy`` cache, producing wasted I/O on local filesystems and
67
- ``.nfsXXXX`` silly-rename files plus ``SIGBUS`` crashes on NFSv3.
68
- The published file is now created exactly once via ``os.link`` and
69
- is never replaced, making the cache safe under arbitrary
70
- concurrent access on local POSIX, NFSv3, Lustre and SMB
71
- (:gh:`986` by `Pierre Guetschel`_)
44
+ - None yet
72
45
 
73
46
  Code health
74
47
  ============
@@ -1 +0,0 @@
1
- __version__ = "1.5.0.dev902"