Repository: braindecode/braindecode

Issue:
`AttributeError: 'Deep4Net' object has no attribute 'conv_spat'`
The following works:
```python
from braindecode.models import Deep4Net

model = Deep4Net(
    n_chans=64,  # Number of EEG channels
    n_outputs=2,  # Number of output classes
    n_times=500,  # Length of the input sequence (e.g., 500 time steps)
    input_window_seconds=1.0,
    batch_norm=True,  # Whether to use batch normalization
    drop_prob=0.5,  # Dropout probability
    sfreq=500.0  # Sampling frequency of the EEG data
)
```
But changing `batch_norm=False` gives the following error:
```python
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[13], [line 3](vscode-notebook-cell:?execution_count=13&line=3)
      1 from braindecode.models import Deep4Net
----> [3](vscode-notebook-cell:?execution_count=13&line=3) model = Deep4Net(
      4     n_chans=64,  # Number of EEG channels
      5     n_outputs=2,  # Number of output classes
      6     n_times=500,  # Length of the input sequence (e.g., 500 time steps)
      7     input_window_seconds=1.0,
      8     batch_norm=False,  # Whether to use batch normalization
      9     drop_prob=0.5,  # Dropout probability
     10     sfreq=500.0  # Sampling frequency of the EEG data
     11 )
     13 # --- Instantiate the BraindecodeEncoder model ---
     14 # model = models.BraindecodeEncoder(
     15 #     input_features=64,  # 64 channels
   (...)     27 #     sfreq=500.0  # Sampling frequency of the EEG data
     28 # )

File /envs/eeg/lib/python3.12/site-packages/braindecode/models/deep4.py:302, in Deep4Net.__init__(***failed resolving arguments***)
    300     init.xavier_uniform_(self.conv_time_spat.conv_spat.weight, gain=1)
    301     if not self.batch_norm:
--> [302](https://vscode-remote+ssh-002dremote-002bmpi-005fworkstation.vscode-resource.vscode-cdn.net/envs/eeg/lib/python3.12/site-packages/braindecode/models/deep4.py:302)         init.constant_(self.conv_spat.bias, 0)
    303 if self.batch_norm:
    304     init.constant_(self.bnorm.weight, 1)

File /envs/eeg/lib/python3.12/site-packages/torch/nn/modules/module.py:1928, in Module.__getattr__(self, name)
   1926     if name in modules:
   1927         return modules[name]
-> [1928](https://vscode-remote+ssh-002dremote-002bmpi-005fworkstation.vscode-resource.vscode-cdn.net/envs/eeg/lib/python3.12/site-packages/torch/nn/modules/module.py:1928) raise AttributeError(
   1929     f"'{type(self).__name__}' object has no attribute '{name}'"
   1930 )

AttributeError: 'Deep4Net' object has no attribute 'conv_spat'
```
`AttributeError: 'EEGConformer' object has no attribute 'final_fc_length'`
The following:
```python
from braindecode.models import EEGConformer

model = EEGConformer(
    n_chans=64,  # Number of EEG channels
    n_outputs=2,  # Number of output classes
    n_times=500,  # Length of the input sequence (e.g., 500 time steps)
    final_fc_length=120,
    input_window_seconds=1.0,
    return_features=True,
    drop_prob=0.5,  # Dropout probability
    sfreq=500.0  # Sampling frequency of the EEG data
)
```
gives the following error:
```python
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[3], [line 3](vscode-notebook-cell:?execution_count=3&line=3)
      1 from braindecode.models import EEGConformer
----> [3](vscode-notebook-cell:?execution_count=3&line=3) model = EEGConformer(
      4     n_chans=64,  # Number of EEG channels
      5     n_outputs=2,  # Number of output classes
      6     n_times=500,  # Length of the input sequence (e.g., 500 time steps)
      7     final_fc_length=120,
      8     input_window_seconds=1.0,
      9     return_features=True,
     10     drop_prob=0.5,  # Dropout probability
     11     sfreq=500.0  # Sampling frequency of the EEG data
     12 )
     13 model

File /envs/eeg/lib/python3.12/site-packages/braindecode/models/eegconformer.py:163, in EEGConformer.__init__(***failed resolving arguments***)
    152     self.final_fc_length = self.get_fc_size()
    154 self.transformer = _TransformerEncoder(
    155     att_depth=att_depth,
    156     emb_size=n_filters_time,
   (...)    159     activation=activation_transfor,
    160 )
    162 self.fc = _FullyConnected(
--> [163](https://vscode-remote+ssh-002dremote-002bmpi-005fworkstation.vscode-resource.vscode-cdn.net/envs/eeg/lib/python3.12/site-packages/braindecode/models/eegconformer.py:163)     final_fc_length=self.final_fc_length, activation=activation
    164 )
    166 self.final_layer = nn.Linear(self.fc.hidden_channels, self.n_outputs)

File /envs/eeg/lib/python3.12/site-packages/torch/nn/modules/module.py:1928, in Module.__getattr__(self, name)
   1926     if name in modules:
   1927         return modules[name]
-> [1928](https://vscode-remote+ssh-002dremote-002bmpi-005fworkstation.vscode-resource.vscode-cdn.net/envs/eeg/lib/python3.12/site-packages/torch/nn/modules/module.py:1928) raise AttributeError(
   1929     f"'{type(self).__name__}' object has no attribute '{name}'"
   1930 )

AttributeError: 'EEGConformer' object has no attribute 'final_fc_length'
```
The reason is that the `EEGConformer.__init__` method has the following if-condition, which doesn't set the `self.final_fc_length=final_fc_length` in the case that it's not `"auto"`:
```python
if final_fc_length == "auto":
    assert self.n_times is not None
    self.final_fc_length = self.get_fc_size()
```



Discussion:
I am looking rn @CamiloMartinezM,

thank you for reporting, probably related with new release.
Please use braindecode source when PR #752 is merged @CamiloMartinezM.

pip install git+https://github.com/braindecode/braindecode

thank you for reporting, if find more issue, please let me know.



Patch:
diff --git a/braindecode/models/deep4.py b/braindecode/models/deep4.py
index 9e0dfb48c..4c968d5f0 100644
--- a/braindecode/models/deep4.py
+++ b/braindecode/models/deep4.py
@@ -115,6 +115,7 @@ def __init__(
         batch_norm=True,
         batch_norm_alpha=0.1,
         stride_before_pool=False,
+        # Braindecode EEGModuleMixin parameters
         chs_info=None,
         input_window_seconds=None,
         sfreq=None,
@@ -299,7 +300,7 @@ def add_conv_pool_block(
         if self.split_first_layer:
             init.xavier_uniform_(self.conv_time_spat.conv_spat.weight, gain=1)
             if not self.batch_norm:
-                init.constant_(self.conv_spat.bias, 0)
+                init.constant_(self.conv_time_spat.conv_spat.bias, 0)
         if self.batch_norm:
             init.constant_(self.bnorm.weight, 1)
             init.constant_(self.bnorm.bias, 0)
diff --git a/braindecode/models/eegconformer.py b/braindecode/models/eegconformer.py
index e84ab5d23..4a1afc178 100644
--- a/braindecode/models/eegconformer.py
+++ b/braindecode/models/eegconformer.py
@@ -2,11 +2,8 @@
 #
 # License: BSD (3-clause)
 import warnings
-from typing import Optional
 
 import torch
-import torch.nn.functional as F
-from einops import rearrange
 from einops.layers.torch import Rearrange
 from torch import Tensor, nn
 
@@ -150,6 +147,8 @@ def __init__(
         if final_fc_length == "auto":
             assert self.n_times is not None
             self.final_fc_length = self.get_fc_size()
+        else:
+            self.final_fc_length = final_fc_length
 
         self.transformer = _TransformerEncoder(
             att_depth=att_depth,
diff --git a/docs/whats_new.rst b/docs/whats_new.rst
index 902afc614..d94d9d3f7 100644
--- a/docs/whats_new.rst
+++ b/docs/whats_new.rst
@@ -25,6 +25,7 @@ Enhancements
 
 Bugs
 ~~~~
+- Fix initialization of :class:`braindecode.models.Deep4Net` (:gh:`752` by `Bruno Aristimunha`_)
 
 API changes
 ~~~~~~~~~~~


Test patch:
diff --git a/test/unit_tests/models/test_models.py b/test/unit_tests/models/test_models.py
index 777bfcf61..c02ef1034 100644
--- a/test/unit_tests/models/test_models.py
+++ b/test/unit_tests/models/test_models.py
@@ -1473,4 +1473,30 @@ def test_eegnex_final_layer_in_features(n_times_input):
         n_times=n_times_input
     )
 
-    print(model)
\ No newline at end of file
+    print(model)
+
+@pytest.mark.parametrize("batch_norm", [True, False])
+def test_batchnorm_deep4net(batch_norm):
+    """
+    Test the number of trainable parameters in Deep4Net model.
+    """
+    model = Deep4Net(n_outputs=2, n_chans=22, n_times=1000, batch_norm=batch_norm)
+    
+    assert model is not None
+
+def test_fc_length_eegconformer():
+    """
+    Test the number of trainable parameters in EEGConformer model.
+    """
+    model = EEGConformer(
+        n_chans=64,  # Number of EEG channels
+        n_outputs=2,  # Number of output classes
+        n_times=500,  # Length of the input sequence (e.g., 500 time steps)
+        final_fc_length=120,
+        input_window_seconds=1.0,
+        return_features=True,
+        drop_prob=0.5,  # Dropout probability
+        sfreq=500.0  # Sampling frequency of the EEG data
+    )
+
+    assert model is not None
\ No newline at end of file