braindecode 1.6.1.dev1054__tar.gz → 1.6.1.dev1064__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 (172) hide show
  1. {braindecode-1.6.1.dev1054/braindecode.egg-info → braindecode-1.6.1.dev1064}/PKG-INFO +1 -1
  2. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/eegneuralnet.py +41 -0
  3. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/atcnet.py +118 -1
  4. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/eegtcnet.py +62 -27
  5. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/sstdpn.py +10 -4
  6. braindecode-1.6.1.dev1064/braindecode/version.py +1 -0
  7. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064/braindecode.egg-info}/PKG-INFO +1 -1
  8. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/whats_new.rst +41 -0
  9. braindecode-1.6.1.dev1054/braindecode/version.py +0 -1
  10. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/LICENSE.txt +0 -0
  11. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/MANIFEST.in +0 -0
  12. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/NOTICE.txt +0 -0
  13. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/README.rst +0 -0
  14. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/__init__.py +0 -0
  15. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/augmentation/__init__.py +0 -0
  16. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/augmentation/base.py +0 -0
  17. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/augmentation/functional.py +0 -0
  18. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/augmentation/transforms.py +0 -0
  19. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/classifier.py +0 -0
  20. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/__init__.py +0 -0
  21. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/base.py +0 -0
  22. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/bbci.py +0 -0
  23. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/bcicomp.py +0 -0
  24. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/bids/__init__.py +0 -0
  25. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/bids/datasets.py +0 -0
  26. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/bids/format.py +0 -0
  27. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/bids/hub.py +0 -0
  28. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/bids/hub_format.py +0 -0
  29. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/bids/hub_io.py +0 -0
  30. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/bids/hub_validation.py +0 -0
  31. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/bids/iterable.py +0 -0
  32. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/chb_mit.py +0 -0
  33. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/mne.py +0 -0
  34. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/moabb.py +0 -0
  35. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/nmt.py +0 -0
  36. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/registry.py +0 -0
  37. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/siena.py +0 -0
  38. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  39. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/sleep_physionet.py +0 -0
  40. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/tuh.py +0 -0
  41. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/utils.py +0 -0
  42. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datasets/xy.py +0 -0
  43. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datautil/__init__.py +0 -0
  44. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datautil/channel_utils.py +0 -0
  45. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datautil/hub_formats.py +0 -0
  46. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datautil/serialization.py +0 -0
  47. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/datautil/util.py +0 -0
  48. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/functional/__init__.py +0 -0
  49. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/functional/functions.py +0 -0
  50. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/functional/initialization.py +0 -0
  51. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/__init__.py +0 -0
  52. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/attentionbasenet.py +0 -0
  53. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/attn_sleep.py +0 -0
  54. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/base.py +0 -0
  55. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/bendr.py +0 -0
  56. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/biot.py +0 -0
  57. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/brainmodule.py +0 -0
  58. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/cbramod.py +0 -0
  59. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/codebrain.py +0 -0
  60. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/config.py +0 -0
  61. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/contrawr.py +0 -0
  62. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/ctnet.py +0 -0
  63. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/deep4.py +0 -0
  64. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/deepsleepnet.py +0 -0
  65. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/dgcnn.py +0 -0
  66. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/eegconformer.py +0 -0
  67. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/eegdino.py +0 -0
  68. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/eeginception_erp.py +0 -0
  69. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/eeginception_mi.py +0 -0
  70. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/eegitnet.py +0 -0
  71. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/eegminer.py +0 -0
  72. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/eegnet.py +0 -0
  73. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/eegnex.py +0 -0
  74. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/eegpt.py +0 -0
  75. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/eegsimpleconv.py +0 -0
  76. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/eegsym.py +0 -0
  77. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/emg2qwerty.py +0 -0
  78. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/fbcnet.py +0 -0
  79. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/fblightconvnet.py +0 -0
  80. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/fbmsnet.py +0 -0
  81. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/hybrid.py +0 -0
  82. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/ifnet.py +0 -0
  83. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/interpolated.py +0 -0
  84. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/labram.py +0 -0
  85. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/luna.py +0 -0
  86. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/medformer.py +0 -0
  87. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/meta_neuromotor.py +0 -0
  88. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/msvtnet.py +0 -0
  89. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/patchedtransformer.py +0 -0
  90. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/reve.py +0 -0
  91. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/sccnet.py +0 -0
  92. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/shallow_fbcsp.py +0 -0
  93. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/signal_jepa.py +0 -0
  94. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/sinc_shallow.py +0 -0
  95. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
  96. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  97. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/sparcnet.py +0 -0
  98. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/summary.csv +0 -0
  99. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/syncnet.py +0 -0
  100. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/tcn.py +0 -0
  101. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/tidnet.py +0 -0
  102. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/tsinception.py +0 -0
  103. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/usleep.py +0 -0
  104. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/models/util.py +0 -0
  105. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/modules/__init__.py +0 -0
  106. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/modules/activation.py +0 -0
  107. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/modules/attention.py +0 -0
  108. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/modules/blocks.py +0 -0
  109. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/modules/convolution.py +0 -0
  110. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/modules/filter.py +0 -0
  111. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/modules/interpolation.py +0 -0
  112. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/modules/layers.py +0 -0
  113. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/modules/linear.py +0 -0
  114. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/modules/parametrization.py +0 -0
  115. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/modules/stats.py +0 -0
  116. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/modules/util.py +0 -0
  117. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/modules/wrapper.py +0 -0
  118. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/preprocessing/__init__.py +0 -0
  119. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
  120. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/preprocessing/mne_preprocess.py +0 -0
  121. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/preprocessing/preprocess.py +0 -0
  122. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/preprocessing/util.py +0 -0
  123. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/preprocessing/windowers.py +0 -0
  124. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/regressor.py +0 -0
  125. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/samplers/__init__.py +0 -0
  126. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/samplers/base.py +0 -0
  127. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/samplers/ssl.py +0 -0
  128. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/training/__init__.py +0 -0
  129. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/training/callbacks.py +0 -0
  130. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/training/losses.py +0 -0
  131. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/training/scoring.py +0 -0
  132. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/util.py +0 -0
  133. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/visualization/__init__.py +0 -0
  134. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/visualization/attribution.py +0 -0
  135. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/visualization/confusion_matrices.py +0 -0
  136. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/visualization/frequency.py +0 -0
  137. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/visualization/metrics.py +0 -0
  138. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/visualization/sanity.py +0 -0
  139. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode/visualization/topology.py +0 -0
  140. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode.egg-info/SOURCES.txt +0 -0
  141. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode.egg-info/dependency_links.txt +0 -0
  142. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode.egg-info/requires.txt +0 -0
  143. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/braindecode.egg-info/top_level.txt +0 -0
  144. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/Makefile +0 -0
  145. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/_templates/autosummary/class.rst +0 -0
  146. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  147. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/_templates/autosummary/function.rst +0 -0
  148. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  149. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/api.rst +0 -0
  150. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/cite.rst +0 -0
  151. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/conf.py +0 -0
  152. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/help.rst +0 -0
  153. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/index.rst +0 -0
  154. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/install/install.rst +0 -0
  155. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/install/install_pip.rst +0 -0
  156. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/install/install_source.rst +0 -0
  157. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/models/categorization/attention.rst +0 -0
  158. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/models/categorization/channel.rst +0 -0
  159. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/models/categorization/convolution.rst +0 -0
  160. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/models/categorization/filterbank.rst +0 -0
  161. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/models/categorization/gnn.rst +0 -0
  162. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/models/categorization/interpretable.rst +0 -0
  163. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/models/categorization/lbm.rst +0 -0
  164. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/models/categorization/recurrent.rst +0 -0
  165. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/models/categorization/spd.rst +0 -0
  166. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/models/models.rst +0 -0
  167. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/models/models_categorization.rst +0 -0
  168. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/models/models_table.rst +0 -0
  169. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/models/models_visualization.rst +0 -0
  170. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/docs/sg_execution_times.rst +0 -0
  171. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/pyproject.toml +0 -0
  172. {braindecode-1.6.1.dev1054 → braindecode-1.6.1.dev1064}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.6.1.dev1054
3
+ Version: 1.6.1.dev1064
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>
@@ -7,6 +7,7 @@
7
7
  import abc
8
8
  import inspect
9
9
  import logging
10
+ import warnings
10
11
  from typing import Literal
11
12
 
12
13
  import mne
@@ -41,6 +42,7 @@ def _get_model(model: str):
41
42
 
42
43
  class _EEGNeuralNet(NeuralNet, abc.ABC):
43
44
  signal_args_set_ = False
45
+ _warned_drop_last_ = False
44
46
 
45
47
  @property
46
48
  def log(self):
@@ -267,6 +269,44 @@ class _EEGNeuralNet(NeuralNet, abc.ABC):
267
269
  X = X.get_data(units="uV")
268
270
  return super().get_dataset(X, y)
269
271
 
272
+ def get_iterator(self, dataset, training=False):
273
+ iterator = super().get_iterator(dataset, training=training)
274
+ # Warn (once per fit) if drop_last would discard every training batch,
275
+ # e.g. a training set smaller than batch_size. This silently skips
276
+ # training without raising any error, which is hard to diagnose.
277
+ if training and not self._warned_drop_last_:
278
+ self._warn_if_training_batches_dropped(iterator)
279
+ return iterator
280
+
281
+ def _warn_if_training_batches_dropped(self, loader):
282
+ """Warn if ``drop_last`` discards all training batches.
283
+
284
+ With ``iterator_train__drop_last=True`` (the braindecode default), a
285
+ training set smaller than ``batch_size`` yields zero batches, so no
286
+ forward/backward pass runs and the model is left untrained without any
287
+ error. We inspect the resolved training ``DataLoader`` (after
288
+ ``train_split`` has been applied), so the count reflects the actual
289
+ number of training examples.
290
+ """
291
+ self._warned_drop_last_ = True
292
+ if not getattr(loader, "drop_last", False):
293
+ return
294
+ batch_size = getattr(loader, "batch_size", None)
295
+ try:
296
+ n_train = len(loader.dataset)
297
+ except TypeError:
298
+ return # e.g. an IterableDataset whose length is unknown
299
+ if not batch_size or n_train == 0 or n_train >= batch_size:
300
+ return
301
+ warnings.warn(
302
+ f"The training set has {n_train} example(s), which is smaller than "
303
+ f"batch_size={batch_size}. With iterator_train__drop_last=True "
304
+ f"(the braindecode default), all training batches are dropped and "
305
+ f"the model is not trained. Reduce batch_size to at most {n_train}, "
306
+ f"or pass iterator_train__drop_last=False.",
307
+ UserWarning,
308
+ )
309
+
270
310
  def partial_fit(self, X, y=None, classes=None, **fit_params):
271
311
  """Fit the module.
272
312
 
@@ -366,6 +406,7 @@ class _EEGNeuralNet(NeuralNet, abc.ABC):
366
406
  the module and to the ``self.train_split`` call.
367
407
  """
368
408
  # this needs to be executed before the net is initialized:
409
+ self._warned_drop_last_ = False # re-check on every fresh fit
369
410
  if not self.signal_args_set_:
370
411
  self._set_signal_args(X, y, classes=None)
371
412
  self.signal_args_set_ = True
@@ -2,14 +2,21 @@
2
2
  #
3
3
  # License: BSD (3-clause)
4
4
  import math
5
+ from typing import Optional
5
6
 
6
7
  import torch
7
8
  from einops.layers.torch import Rearrange
8
9
  from mne.utils import warn
9
10
  from torch import nn
11
+ from torch.nn.utils.parametrize import is_parametrized, register_parametrization
10
12
 
11
13
  from braindecode.models.base import EEGModuleMixin
12
- from braindecode.modules import CausalConv1d, Ensure4d, MaxNormLinear
14
+ from braindecode.modules import (
15
+ CausalConv1d,
16
+ Ensure4d,
17
+ MaxNormLinear,
18
+ MaxNormParametrize,
19
+ )
13
20
 
14
21
 
15
22
  class ATCNet(EEGModuleMixin, nn.Module):
@@ -213,6 +220,16 @@ class ATCNet(EEGModuleMixin, nn.Module):
213
220
  max_norm_const : float
214
221
  Maximum L2-norm constraint imposed on weights of the last
215
222
  fully-connected layer. Defaults to 0.25.
223
+ conv_max_norm_const : float | None
224
+ If not ``None``, applies a max-norm constraint (via a weight
225
+ parametrization) to the convolution kernels of :class:`_ConvBlock` and
226
+ :class:`_TCNResidualBlock`, matching the official implementation which
227
+ uses ``0.6``. When ``None`` (default), no constraint is applied to those
228
+ layers, preserving the previous behavior. The complementary ``L2``
229
+ weight decay of the official code can be obtained from
230
+ :meth:`source_optimizer_param_groups`.
231
+
232
+ .. versionadded:: 1.6.1
216
233
 
217
234
  Notes
218
235
  -----
@@ -257,6 +274,7 @@ class ATCNet(EEGModuleMixin, nn.Module):
257
274
  tcn_activation: type[nn.Module] = nn.ELU,
258
275
  concat=False,
259
276
  max_norm_const=0.25,
277
+ conv_max_norm_const: Optional[float] = None,
260
278
  chs_info=None,
261
279
  n_times=None,
262
280
  ):
@@ -325,6 +343,7 @@ class ATCNet(EEGModuleMixin, nn.Module):
325
343
  self.tcn_activation = tcn_activation
326
344
  self.concat = concat
327
345
  self.max_norm_const = max_norm_const
346
+ self.conv_max_norm_const = conv_max_norm_const
328
347
  self.tcn_n_filters = int(self.conv_block_depth_mult * self.conv_block_n_filters)
329
348
  map = dict()
330
349
  for w in range(self.n_windows):
@@ -346,6 +365,7 @@ class ATCNet(EEGModuleMixin, nn.Module):
346
365
  pool_size_2=conv_block_pool_size_2,
347
366
  depth_mult=conv_block_depth_mult,
348
367
  dropout=conv_block_dropout,
368
+ conv_max_norm=self.conv_max_norm_const,
349
369
  )
350
370
 
351
371
  self.F2 = int(conv_block_depth_mult * conv_block_n_filters)
@@ -375,6 +395,7 @@ class ATCNet(EEGModuleMixin, nn.Module):
375
395
  dropout=self.tcn_dropout,
376
396
  activation=self.tcn_activation,
377
397
  dilation=2**i,
398
+ conv_max_norm=self.conv_max_norm_const,
378
399
  )
379
400
  for i in range(self.tcn_depth)
380
401
  ]
@@ -458,6 +479,93 @@ class ATCNet(EEGModuleMixin, nn.Module):
458
479
 
459
480
  return self.out_fun(sw_concat_agg)
460
481
 
482
+ def source_optimizer_param_groups(
483
+ self,
484
+ conv_weight_decay: float = 0.009,
485
+ dense_weight_decay: float = 0.5,
486
+ ) -> list[dict]:
487
+ r"""Source-faithful optimizer parameter groups for ATCNet.
488
+
489
+ The official Keras implementation applies ``L2`` weight decay only to the
490
+ convolution / TCN kernels (``conv_weightDecay = 0.009``) and to the final
491
+ dense layer (``dense_weightDecay = 0.5``); biases, BatchNorm and attention
492
+ weights are left undecayed. This reproduces the Keras ``L2`` kernel penalty
493
+ only for optimizers that implement ``weight_decay`` as a coupled L2 term,
494
+ e.g. :class:`torch.optim.SGD` or :class:`torch.optim.Adam` (as used by the
495
+ official code). For decoupled-weight-decay optimizers such as
496
+ :class:`torch.optim.AdamW`, ``weight_decay`` is *not* equivalent to a Keras
497
+ ``L2`` penalty.
498
+
499
+ Parameters
500
+ ----------
501
+ conv_weight_decay : float
502
+ Weight decay applied to the convolution and TCN kernels. Defaults to
503
+ ``0.009`` as in the official code.
504
+ dense_weight_decay : float
505
+ Weight decay applied to the final (dense) layer weights. Defaults to
506
+ ``0.5`` as in the official code.
507
+
508
+ Returns
509
+ -------
510
+ list of dict
511
+ Parameter groups ready to be passed to a ``torch.optim`` optimizer:
512
+ convolution/TCN kernels, final dense weights, and everything else
513
+ (no decay).
514
+
515
+ Examples
516
+ --------
517
+ >>> model = ATCNet(n_chans=22, n_outputs=4, n_times=1125) # doctest: +SKIP
518
+ >>> opt = torch.optim.Adam(model.source_optimizer_param_groups()) # doctest: +SKIP
519
+ """
520
+
521
+ def weight_leaf(module):
522
+ # Return the leaf weight Parameter, accounting for a registered
523
+ # max-norm parametrization (``conv_max_norm_const`` / MaxNormLinear).
524
+ if is_parametrized(module, "weight"):
525
+ return module.parametrizations.weight.original
526
+ return module.weight
527
+
528
+ conv_weights: list[nn.Parameter] = []
529
+ dense_weights: list[nn.Parameter] = []
530
+ decayed_ids: set[int] = set()
531
+
532
+ # Convolution / TCN kernels (Keras L2 = 0.009).
533
+ for parent in (self.conv_block, self.temporal_conv_nets):
534
+ for module in parent.modules():
535
+ if isinstance(module, (nn.Conv1d, nn.Conv2d)):
536
+ weight = weight_leaf(module)
537
+ conv_weights.append(weight)
538
+ decayed_ids.add(id(weight))
539
+
540
+ # Final dense / readout weights (Keras L2 = 0.5).
541
+ for module in self.final_layer.modules():
542
+ if isinstance(module, nn.Linear):
543
+ weight = weight_leaf(module)
544
+ dense_weights.append(weight)
545
+ decayed_ids.add(id(weight))
546
+
547
+ # Everything else (biases, BatchNorm, attention) is left undecayed.
548
+ other = [p for p in self.parameters() if id(p) not in decayed_ids]
549
+
550
+ return [
551
+ {"params": conv_weights, "weight_decay": conv_weight_decay},
552
+ {"params": dense_weights, "weight_decay": dense_weight_decay},
553
+ {"params": other, "weight_decay": 0.0},
554
+ ]
555
+
556
+
557
+ def _register_max_norm(max_norm, *convs):
558
+ """Register a max-norm weight parametrization on each given convolution.
559
+
560
+ No-op when ``max_norm`` is ``None`` or a passed layer is not a convolution
561
+ (e.g. an ``nn.Identity`` residual shortcut).
562
+ """
563
+ if max_norm is None:
564
+ return
565
+ for conv in convs:
566
+ if isinstance(conv, (nn.Conv1d, nn.Conv2d)):
567
+ register_parametrization(conv, "weight", MaxNormParametrize(max_norm))
568
+
461
569
 
462
570
  class _ConvBlock(nn.Module):
463
571
  r"""Convolutional block proposed in ATCNet [1]_, inspired by the EEGNet.
@@ -487,6 +595,7 @@ class _ConvBlock(nn.Module):
487
595
  pool_size_2=7,
488
596
  depth_mult=2,
489
597
  dropout=0.3,
598
+ conv_max_norm: Optional[float] = None,
490
599
  ):
491
600
  super().__init__()
492
601
 
@@ -534,6 +643,9 @@ class _ConvBlock(nn.Module):
534
643
 
535
644
  self.drop3 = nn.Dropout2d(dropout)
536
645
 
646
+ # Optional source-faithful max-norm constraint on the conv kernels.
647
+ _register_max_norm(conv_max_norm, self.conv1, self.conv2, self.conv3)
648
+
537
649
  def forward(self, X):
538
650
  # ----- Temporal convolution -----
539
651
  # Dimension: (batch_size, 1, T, C)
@@ -662,6 +774,7 @@ class _TCNResidualBlock(nn.Module):
662
774
  dropout=0.3,
663
775
  activation: type[nn.Module] = nn.ELU,
664
776
  dilation=1,
777
+ conv_max_norm: Optional[float] = None,
665
778
  ):
666
779
  super().__init__()
667
780
  self.activation = activation()
@@ -706,6 +819,10 @@ class _TCNResidualBlock(nn.Module):
706
819
  else:
707
820
  self.reshaping_conv = nn.Identity()
708
821
 
822
+ # Optional source-faithful max-norm constraint on the conv kernels
823
+ # (reshaping_conv may be nn.Identity, which the helper skips).
824
+ _register_max_norm(conv_max_norm, self.conv1, self.conv2, self.reshaping_conv)
825
+
709
826
  def forward(self, X):
710
827
  # Dimension: (batch_size, F2, Tw)
711
828
  # ----- Double dilated convolutions -----
@@ -9,6 +9,7 @@ import torch.nn as nn
9
9
  from einops.layers.torch import Rearrange
10
10
 
11
11
  from braindecode.models.base import EEGModuleMixin
12
+ from braindecode.models.util import _disable_batch_norm_training_if_batch_size_one
12
13
  from braindecode.modules import Chomp1d, MaxNormLinear
13
14
 
14
15
 
@@ -33,8 +34,10 @@ class EEGTCNet(EEGModuleMixin, nn.Module):
33
34
  Number of temporal filters in the first convolutional layer. Default is 8.
34
35
  kern_length : int, optional
35
36
  Length of the temporal kernel in the first convolutional layer. Default is 64.
36
- dropout : float, optional
37
- Dropout rate. Default is 0.5.
37
+ drop_prob : float, optional
38
+ Default dropout rate, used for both the EEGNet front-end and the TCN
39
+ block unless overridden by ``drop_prob_eeg`` / ``drop_prob_tcn``.
40
+ Default is 0.5.
38
41
  depth : int, optional
39
42
  Number of residual blocks in the TCN. Default is 2.
40
43
  kernel_size : int, optional
@@ -44,6 +47,20 @@ class EEGTCNet(EEGModuleMixin, nn.Module):
44
47
  max_norm_const : float
45
48
  Maximum L2-norm constraint imposed on weights of the last
46
49
  fully-connected layer. Defaults to 0.25.
50
+ drop_prob_eeg : float | None, optional
51
+ Dropout rate for the EEGNet front-end. If ``None`` (default), falls back
52
+ to ``drop_prob``. The source/paper uses ``0.2`` for BCI IV 2a.
53
+ drop_prob_tcn : float | None, optional
54
+ Dropout rate for the TCN block. If ``None`` (default), falls back to
55
+ ``drop_prob``. The source/paper uses ``0.3`` for BCI IV 2a.
56
+ tcn_batch_norm : bool, optional
57
+ If ``True`` (default), insert a :class:`~torch.nn.BatchNorm1d` after each
58
+ TCN convolution and use a bias in the residual ``1x1`` downsample, matching
59
+ the original Keras source. Set to ``False`` to recover the previous
60
+ braindecode architecture (e.g. to load checkpoints trained before this
61
+ change). Default is ``True``.
62
+
63
+ .. versionadded:: 1.6.1
47
64
 
48
65
  References
49
66
  ----------
@@ -72,6 +89,9 @@ class EEGTCNet(EEGModuleMixin, nn.Module):
72
89
  kernel_size: int = 4,
73
90
  filters: int = 12,
74
91
  max_norm_const: float = 0.25,
92
+ drop_prob_eeg: float | None = None,
93
+ drop_prob_tcn: float | None = None,
94
+ tcn_batch_norm: bool = True,
75
95
  ):
76
96
  super().__init__(
77
97
  n_outputs=n_outputs,
@@ -85,6 +105,11 @@ class EEGTCNet(EEGModuleMixin, nn.Module):
85
105
 
86
106
  self.activation = activation
87
107
  self.drop_prob = drop_prob
108
+ # Separate dropout rates for the EEGNet front-end and the TCN block;
109
+ # fall back to ``drop_prob`` when not explicitly set.
110
+ self.drop_prob_eeg = drop_prob if drop_prob_eeg is None else drop_prob_eeg
111
+ self.drop_prob_tcn = drop_prob if drop_prob_tcn is None else drop_prob_tcn
112
+ self.tcn_batch_norm = tcn_batch_norm
88
113
  self.depth_multiplier = depth_multiplier
89
114
  self.filter_1 = filter_1
90
115
  self.kern_length = kern_length
@@ -103,7 +128,7 @@ class EEGTCNet(EEGModuleMixin, nn.Module):
103
128
  filter_1=self.filter_1,
104
129
  kern_length=self.kern_length,
105
130
  depth_multiplier=self.depth_multiplier,
106
- drop_prob=self.drop_prob,
131
+ drop_prob=self.drop_prob_eeg,
107
132
  activation=self.activation,
108
133
  )
109
134
  self.arrange_dim_eegnet = Rearrange(
@@ -116,8 +141,9 @@ class EEGTCNet(EEGModuleMixin, nn.Module):
116
141
  depth=self.depth,
117
142
  kernel_size=self.kernel_size,
118
143
  filters=self.filters,
119
- drop_prob=self.drop_prob,
144
+ drop_prob=self.drop_prob_tcn,
120
145
  activation=self.activation,
146
+ batch_norm=self.tcn_batch_norm,
121
147
  )
122
148
 
123
149
  # Classification Block
@@ -127,6 +153,7 @@ class EEGTCNet(EEGModuleMixin, nn.Module):
127
153
  max_norm_val=self.max_norm_const,
128
154
  )
129
155
 
156
+ @_disable_batch_norm_training_if_batch_size_one
130
157
  def forward(self, x: torch.Tensor) -> torch.Tensor:
131
158
  """
132
159
  Forward pass of the EEGTCNet model.
@@ -277,6 +304,7 @@ class _TCNBlock(nn.Module):
277
304
  filters: int,
278
305
  drop_prob: float,
279
306
  activation: type[nn.Module] = nn.ELU,
307
+ batch_norm: bool = True,
280
308
  ):
281
309
  super().__init__()
282
310
  self.activation = activation()
@@ -284,10 +312,15 @@ class _TCNBlock(nn.Module):
284
312
  self.depth = depth
285
313
  self.filters = filters
286
314
  self.kernel_size = kernel_size
315
+ self.batch_norm = batch_norm
287
316
 
288
317
  self.layers = nn.ModuleList()
318
+ # The Keras source uses a bias on the residual 1x1 downsample, paired
319
+ # with the per-conv BatchNorm; the previous braindecode default omitted
320
+ # both. Keeping them on the same flag makes ``batch_norm=False`` reproduce
321
+ # the legacy architecture exactly.
289
322
  self.downsample = (
290
- nn.Conv1d(input_dimension, filters, kernel_size=1, bias=False)
323
+ nn.Conv1d(input_dimension, filters, kernel_size=1, bias=batch_norm)
291
324
  if input_dimension != filters
292
325
  else None
293
326
  )
@@ -295,32 +328,34 @@ class _TCNBlock(nn.Module):
295
328
  for i in range(depth):
296
329
  dilation = 2**i
297
330
  padding = (kernel_size - 1) * dilation
331
+ in_dim = input_dimension if i == 0 else filters
298
332
  conv_block = nn.Sequential(
299
- nn.Conv1d(
300
- in_channels=input_dimension if i == 0 else filters,
301
- out_channels=filters,
302
- kernel_size=kernel_size,
303
- dilation=dilation,
304
- padding=padding,
305
- bias=False,
306
- ),
307
- Chomp1d(padding),
308
- self.activation,
309
- nn.Dropout(self.drop_prob),
310
- nn.Conv1d(
311
- in_channels=filters,
312
- out_channels=filters,
313
- kernel_size=kernel_size,
314
- dilation=dilation,
315
- padding=padding,
316
- bias=False,
317
- ),
318
- Chomp1d(padding),
319
- self.activation,
320
- nn.Dropout(self.drop_prob),
333
+ *self._conv_unit(in_dim, dilation, padding),
334
+ *self._conv_unit(filters, dilation, padding),
321
335
  )
322
336
  self.layers.append(conv_block)
323
337
 
338
+ def _conv_unit(self, in_channels: int, dilation: int, padding: int):
339
+ # Conv -> Chomp -> [BatchNorm] -> activation -> Dropout, as in the
340
+ # original EEG-TCNet Keras implementation.
341
+ unit = [
342
+ nn.Conv1d(
343
+ in_channels=in_channels,
344
+ out_channels=self.filters,
345
+ kernel_size=self.kernel_size,
346
+ dilation=dilation,
347
+ padding=padding,
348
+ bias=False,
349
+ ),
350
+ Chomp1d(padding),
351
+ ]
352
+ if self.batch_norm:
353
+ # Keras BatchNormalization defaults: momentum=0.99 (-> 0.01 in
354
+ # PyTorch convention) and epsilon=1e-3.
355
+ unit.append(nn.BatchNorm1d(self.filters, momentum=0.01, eps=1e-3))
356
+ unit += [self.activation, nn.Dropout(self.drop_prob)]
357
+ return unit
358
+
324
359
  def forward(self, x: torch.Tensor) -> torch.Tensor:
325
360
  # x shape: (batch_size, time_steps, input_dimension)
326
361
  x = x.permute(0, 2, 1) # (batch_size, input_dimension, time_steps)
@@ -183,7 +183,11 @@ class SSTDPN(EEGModuleMixin, nn.Module):
183
183
  This constraint acts as an implicit force to push features away from the origin. Default is 1.0.
184
184
 
185
185
  proto_cpt_std : float, optional
186
- Standard deviation for Intra-class Compactness Prototype initialization. Default is 0.01.
186
+ Standard deviation for Intra-class Compactness Prototype initialization. Default is 1.0,
187
+ matching the source ``torch.randn`` initialization.
188
+
189
+ .. versionchanged:: 1.6.1
190
+ Default changed from ``0.01`` to ``1.0`` to match the original implementation.
187
191
 
188
192
  spt_attn_global_context_kernel : int, optional
189
193
  Kernel size for global context embedding in Spatial-Spectral Attention module.
@@ -231,7 +235,7 @@ class SSTDPN(EEGModuleMixin, nn.Module):
231
235
  mvp_kernel_sizes: Optional[List[int]] = None,
232
236
  return_features: bool = False,
233
237
  proto_sep_maxnorm: float = 1.0,
234
- proto_cpt_std: float = 0.01,
238
+ proto_cpt_std: float = 1.0,
235
239
  spt_attn_global_context_kernel: int = 250,
236
240
  spt_attn_epsilon: float = 1e-5,
237
241
  spt_attn_mode: str = "var",
@@ -327,9 +331,11 @@ class SSTDPN(EEGModuleMixin, nn.Module):
327
331
  """
328
332
 
329
333
  features = self.encoder(x) # (b, feat_dim)
330
- # Renormalize inter-class separation prototypes
334
+ # Renormalize inter-class separation prototypes. ``proto_sep`` has shape
335
+ # (n_outputs, feat_dim); the source constrains each class-row prototype
336
+ # vector (``||s_i|| <= S``), i.e. renorm along dim=0.
331
337
  self.proto_sep.data = torch.renorm(
332
- self.proto_sep.data, p=2, dim=1, maxnorm=self.proto_sep_maxnorm
338
+ self.proto_sep.data, p=2, dim=0, maxnorm=self.proto_sep_maxnorm
333
339
  )
334
340
  logits = torch.einsum("bd,cd->bc", features, self.proto_sep) # (b, n_outputs)
335
341
  logits = self.final_layer(logits)
@@ -0,0 +1 @@
1
+ __version__ = "1.6.1.dev1064"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.6.1.dev1054
3
+ Version: 1.6.1.dev1064
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>
@@ -38,6 +38,17 @@ Enhancements
38
38
  By `Pierre Guetschel`_.
39
39
  - Add :class:`braindecode.models.EEGDINO`, the EEG-DINO self-distillation
40
40
  foundation model (Small/Medium/Large) with pretrained S/M weights. By `Bruno Aristimunha`_.
41
+ - Add separate EEGNet and TCN dropout rates to
42
+ :class:`braindecode.models.EEGTCNet` via the new ``drop_prob_eeg`` and
43
+ ``drop_prob_tcn`` arguments, enabling the source/paper configuration
44
+ (``p_eeg=0.2``, ``p_tcn=0.3``). Both default to ``drop_prob``, so existing
45
+ behavior is unchanged. (:gh:`1060` by `Bruno Aristimunha`_)
46
+ - Add an opt-in ``conv_max_norm_const`` argument and a
47
+ :meth:`~braindecode.models.ATCNet.source_optimizer_param_groups` helper to
48
+ :class:`braindecode.models.ATCNet`, exposing the official implementation's
49
+ convolution/TCN max-norm constraint (``0.6``) and ``L2`` weight-decay groups
50
+ (conv/TCN ``0.009``, dense ``0.5``). Defaults preserve current behavior.
51
+ (:gh:`1061` by `Bruno Aristimunha`_)
41
52
 
42
53
  API and behavior changes
43
54
  ========================
@@ -48,6 +59,16 @@ API and behavior changes
48
59
  :class:`braindecode.models.AttnSleep`), ``TSceptionV1`` (use
49
60
  :class:`braindecode.models.TSception`), and ``BNCI2014001`` (use
50
61
  :class:`braindecode.datasets.BNCI2014_001`). (:gh:`1045` by `Bhargav Kowshik`_)
62
+ - :class:`braindecode.models.EEGTCNet` now inserts a
63
+ :class:`~torch.nn.BatchNorm1d` after each TCN convolution (and uses a bias in
64
+ the residual downsample), matching the original Keras implementation. This
65
+ closes a documented replicability gap but changes the default architecture and
66
+ parameter count; pass ``tcn_batch_norm=False`` to recover the previous
67
+ behavior (e.g. to load checkpoints trained before this change). By
68
+ `Bruno Aristimunha`_.
69
+ - Change the default ``proto_cpt_std`` of :class:`braindecode.models.SSTDPN`
70
+ from ``0.01`` to ``1.0``, matching the source ``torch.randn`` initialization
71
+ of the intra-class compactness prototypes. By `Bruno Aristimunha`_.
51
72
 
52
73
  Requirements
53
74
  ============
@@ -61,6 +82,11 @@ Requirements
61
82
  Bug fixes
62
83
  ==========
63
84
 
85
+ - Fix :class:`braindecode.models.SSTDPN` renormalizing ``proto_sep`` along the
86
+ wrong axis: the inter-class separation prototypes are now constrained per
87
+ class-row (``dim=0``) as in the paper/source (``||s_i|| <= S``), instead of
88
+ across classes (``dim=1``). (:gh:`1059` by `Bruno Aristimunha`_)
89
+
64
90
  - Fix :class:`~braindecode.models.ContraWR`,
65
91
  :class:`~braindecode.models.DeepSleepNet`, and
66
92
  :class:`~braindecode.models.EEGMiner` raising a confusing
@@ -88,9 +114,24 @@ Bug fixes
88
114
  :class:`~braindecode.EEGClassifier` infer the signal dimensions from the data.
89
115
  By `Bhargav Kowshik`_
90
116
 
117
+ - Fix :class:`~braindecode.EEGClassifier` and
118
+ :class:`~braindecode.EEGRegressor` silently skipping all training when the
119
+ training set is smaller than ``batch_size`` (with the default
120
+ ``iterator_train__drop_last=True``). Previously every batch was dropped and
121
+ the model was left untrained without any message; a :class:`UserWarning` is
122
+ now raised telling the user to lower ``batch_size`` or set
123
+ ``iterator_train__drop_last=False``.
124
+ (:gh:`1053` by `Bhargav Kowshik`_)
125
+
91
126
  Code health
92
127
  ============
93
128
 
129
+ - Silence the new "training set smaller than ``batch_size``" warning
130
+ (:gh:`1053`) in the ``test_eegneuralnet`` signal-argument tests, which
131
+ intentionally fit tiny mock data to check argument propagation rather than
132
+ to train. Keeps the warning meaningful by not emitting it on every CI run.
133
+ (:gh:`1056` by `Adam Mounir`_)
134
+
94
135
  - Install CPU-only PyTorch wheels in the ``tests`` and ``docs`` CI
95
136
  workflows via ``UV_TORCH_BACKEND=cpu``. GitHub runners have no GPU, so
96
137
  the default CUDA build pulled ~1.8 GiB of unused ``nvidia-*`` wheels and
@@ -1 +0,0 @@
1
- __version__ = "1.6.1.dev1054"