eegproc.deep_learning.unsupervised.GNN.GCNMTL module

Spatio-spectral GCN-GRU encoder adapted from MTLFuseNet.

Electrodes are nodes of a graph whose adjacency A is fixed and estimated from mutual information. Frequency bands form an ordered sequence of graphs that share the same graph-convolution weights, and a GRU can read that band sequence at each timestep. Graph convolution uses the renormalized adjacency:

A_tilde = A + I
A_hat   = D_tilde^-1/2 A_tilde D_tilde^-1/2
H_B     = ReLU(A_hat V_B W + b)

The same graph-convolution layers, and therefore the same W and b, are reused for every band B.

MTLFuseNet uses differential-entropy node features. This encoder applies the same graph and weight-sharing mechanism to per-timestep channel-band values, so it returns (batch, ceil(timesteps / t_down), emb_dim) like the other EEGProc encoders. Feed differential-entropy features instead of filtered band amplitudes to follow the original method more closely. There is no learned projection after the spectral GRU: with use_spectral_gru=True the output dimension is exactly spectral_gru_units.

BandSeparatedGCNEncoder (learned adjacency) lives in GCN_band_separated.py; the two can be swapped in the same model.

Reference: R. Li et al., “MTLFuseNet: A novel emotion recognition model based on deep latent feature fusion of EEG signals and multi-task learning”, Knowledge-Based Systems 276 (2023), 110756.

eegproc.deep_learning.unsupervised.GNN.GCNMTL.GCNDecoder

alias of GCNMTLDecoder

eegproc.deep_learning.unsupervised.GNN.GCNMTL.GCNEncoder

alias of GCNMTLEncoder

class eegproc.deep_learning.unsupervised.GNN.GCNMTL.GCNMTLDecoder(timesteps, n_channels, n_bands, t_down, gcn_units, temporal_pool_sizes, adjacency, emb_dim=128, dropout=0.1, activation='relu', use_batch_norm=False, graph_add_self_loops=True, graph_symmetrize=True, graph_epsilon=1e-08, name='decoder_gcn_mtl', **kwargs)[source]

Bases: Model

Graph-aware decoder for GCNMTLEncoder latent sequences.

It maps latents back to channel-band signals, for example for autoencoder or reconstruction objectives, using the encoder’s fixed mutual-information adjacency and renormalization. MTLFuseNet does not define a decoder; this is an EEGProc addition.

Parameters:
  • timesteps (int)

  • n_channels (int)

  • n_bands (int)

  • t_down (int)

  • gcn_units (tuple[int, ...])

  • temporal_pool_sizes (tuple[int, ...] | None)

  • emb_dim (int, default: 128)

  • dropout (float, default: 0.1)

  • activation (str, default: 'relu')

  • use_batch_norm (bool, default: False)

  • graph_add_self_loops (bool, default: True)

  • graph_symmetrize (bool, default: True)

  • graph_epsilon (float, default: 1e-08)

  • name (str, default: 'decoder_gcn_mtl')

call(inputs, training=False)[source]
Parameters:

training (bool, default: False)

fix_length(x)[source]
Parameters:

x (Tensor)

Return type:

Tensor

classmethod from_encoder(encoder, name='decoder_gcn_mtl')[source]
Parameters:
Return type:

GCNMTLDecoder

get_config()[source]

Returns the config of the object.

An object config is a Python dictionary (serializable) containing the information needed to re-instantiate it.

Return type:

dict[str, Any]

property n_features: int
class eegproc.deep_learning.unsupervised.GNN.GCNMTL.GCNMTLEncoder(timesteps, t_down, adjacency, n_channels=14, n_bands=3, gcn_units=(64, 32), temporal_pool_sizes=None, emb_dim=None, dropout=0.1, activation='relu', use_batch_norm=False, use_spectral_gru=True, spectral_gru_units=384, spectral_gru_dropout=0.0, graph_add_self_loops=True, graph_symmetrize=True, graph_epsilon=1e-08, graph_self_loop_bias=None, graph_identity_mix=None, graph_adjacency_reg_weight=None, name='encoder_gcn_mtl', **kwargs)[source]

Bases: BaseEncoder

Shared-parameter spatio-spectral GCN-GRU encoder (after MTLFuseNet).

Notes

Inputs have shape (batch, timesteps, n_channels * n_bands) in channel-major order (ch0_band0, ch0_band1, ..., ch1_band0, ...). Outputs have shape (batch, ceil(timesteps / t_down), spectral_gru_units) when use_spectral_gru=True; there is no projection after the GRU.

The adjacency is fixed and must be computed from training data only; estimating it from validation or test subjects leaks their data into the model.

Parameters:
  • timesteps (int)

  • t_down (int)

  • n_channels (int, default: 14)

  • n_bands (int, default: 3)

  • gcn_units (tuple[int, ...], default: (64, 32))

  • temporal_pool_sizes (tuple[int, ...] | None, default: None)

  • emb_dim (int | None, default: None)

  • dropout (float, default: 0.1)

  • activation (str, default: 'relu')

  • use_batch_norm (bool, default: False)

  • use_spectral_gru (bool, default: True)

  • spectral_gru_units (int, default: 384)

  • spectral_gru_dropout (float, default: 0.0)

  • graph_add_self_loops (bool, default: True)

  • graph_symmetrize (bool, default: True)

  • graph_epsilon (float, default: 1e-08)

  • graph_self_loop_bias (float | None, default: None)

  • graph_identity_mix (float | None, default: None)

  • graph_adjacency_reg_weight (float | None, default: None)

  • name (str, default: 'encoder_gcn_mtl')

call(inputs, training=False)[source]

Run the encoder forward pass.

Parameters:

training (bool, default: False)

get_adjacency_matrix()[source]

Return the MTL-normalized shared adjacency used by the GCN.

Return type:

Tensor

get_band_features(inputs, training=False)[source]
Parameters:

training (bool, default: False)

Return type:

dict[str, Tensor]

get_config()[source]

Return serializable configuration for the base encoder.

Return type:

dict[str, Any]

get_raw_adjacency_matrix()[source]

Return the fixed pre-self-loop MI adjacency A.

Return type:

Tensor

property n_features: int

Number of input features per timestep.

eegproc.deep_learning.unsupervised.GNN.GCNMTL.compute_mi_adjacency_from_channels(channel_data, *, n_neighbors=3, random_state=42, zero_diagonal=False)[source]

Compute a symmetric mutual-information channel adjacency.

Parameters:
  • channel_data (array-like, shape (..., n_channels)) – Samples/observations for each EEG channel. All leading dimensions are flattened into the observation dimension.

  • n_neighbors (int, default: 3) – k used by sklearn’s continuous mutual-information estimator.

  • random_state (int, default: 42) – Reproducibility seed for sklearn’s MI estimator.

  • zero_diagonal (bool, default: False) – The MTLFuseNet definition permits i=j, so the default preserves the estimated MI diagonal. Set True only for an ablation where A contains cross-channel MI and self-connectivity comes solely from A_tilde=A+I.

Return type:

ndarray

Notes

Use TRAINING DATA ONLY. Computing A from validation/test subjects leaks information into the graph used by the model.

eegproc.deep_learning.unsupervised.GNN.GCNMTL.compute_mtl_shared_mi_adjacency(inputs, *, n_channels=14, n_bands=3, n_neighbors=3, random_state=42, zero_diagonal=False, band_reduction='mean')[source]

Estimate one shared MTL adjacency from EEGProc channel-band data.

The MTLFuseNet text uses a single A in every graph G_B while the node features V’_B vary by band. If only already-band-separated EEGProc inputs are available, this helper estimates MI independently in each band and reduces the band-wise MI matrices to ONE shared A.

band_reduction='mean' is the default compatibility approximation. If you have the pre-band-split channel signals x_i that MTLFuseNet uses to construct A, prefer compute_mi_adjacency_from_channels directly.

Parameters:
  • n_channels (int, default: 14)

  • n_bands (int, default: 3)

  • n_neighbors (int, default: 3)

  • random_state (int, default: 42)

  • zero_diagonal (bool, default: False)

  • band_reduction (str, default: 'mean')

Return type:

ndarray