Paper · 2021-07-16 · cs.LG, cs.AI
MS-MDA: Multisource Marginal Distribution Adaptation for Cross-subject and Cross-session EEG Emotion Recognition
MS-MDA classifies EEG emotions across subjects and sessions by giving each source subject or session its own domain-specific branch on a shared MLP. Each branch aligns its source with the unlabelled target by MMD, and a discrepancy term ties the branch classifiers together; predictions average them. Author-reported on SEED: 88.56% cross-session and 89.63% cross-subject accuracy.
Domain adaptationTransfer learningEnsembleseegemotion-recognitiondomain-adaptationmulti-sourcemlp
arXivPDFCodeMarkdown13 min read
AI-compiled by claude-haiku-5-5 on 2026-11-08, not yet reviewed by a human. Every claim cites its source; check it when a detail matters.
In plain words
An EEG headset reads brain signals, and the same emotion looks different in every person and on every day the headset is worn. A model trained on earlier people or sessions often does badly on a new one. The usual fix is to pool all the old recordings into one big training set and adapt that pool to the new person. This paper argues that the pool blurs the differences between people and sessions, which are the very thing that makes each recording distinct.
MS-MDA keeps each old person or session as its own source. A small shared network first extracts features common to all recordings. Then each source gets its own small branch that is nudged to look like the new person's data and has its own classifier. A penalty keeps the branches' answers close to one another. For a new recording, the model averages what all the branches say. The authors also find that how the signal is normalised changes results a lot.
TL;DR
- Multi-source domain adaptation for EEG emotion recognition: one branch per source subject or session, each aligned one-to-one with the target §I fig. 3.
- Input is a 310-dimensional vector of differential entropy features (62 channels × 5 bands) §III-D. The network is a shared 3-layer MLP plus small per-branch layers §IV §V-A.
- Author-reported: 88.56 ± 7.80 (cross-session) and 89.63 ± 6.79 (cross-subject) on SEED, 3 classes tab. II.
- Code is MIT-licensed and linked from the paper, but it differs from the paper in several places that change the loss, the optimiser and the reported numbers. See Paper vs code.
Problem
Signals from one EEG session and from one subject have non-stationary, biased distributions, so a model does not transfer across them without adaptation §I. Labelled data is costly to collect. Earlier domain-adaptation work for EEG usually merged all source subjects or sessions into one source domain before aligning it with the target §I §II. The authors argue this breaks the marginal distribution of each source and makes the merged distribution hard to interpret, so the adaptation becomes harder §I.
Method
Setting. Inputs are N labelled source domains, each a subject (cross-subject) or a session (cross-session), and one unlabelled target domain. The target labels are used only for testing §IV alg. 1.
Architecture fig. 3 §IV:
- Common feature extractor (CFE). Shared by all domains. It maps the 310-dimensional input to a 64-dimensional common feature, using a 3-layer MLP with a LeakyReLU after each linear layer §IV §V-A.
- Domain-specific feature extractor (DSFE), one per source. A single linear layer maps 64 to 32, followed by LeakyReLU §IV §V-A. Each DSFE sees the common features of its own source and of the target.
- Domain-specific classifier (DSC), one per source. A single linear layer maps 32 to the number of classes (3 for SEED, 4 for SEED-IV), with no activation §V-A.
Losses. Each branch i compares its source features with the target features using MMD eq. 2. The classifiers are trained with cross-entropy on their own source eq. 3. A discrepancy term penalises disagreement between the branches' predictions on the target eq. 4. The total loss is a weighted sum eq. 5 alg. 1.
\operatorname{MMD}_{\left(X^{S}, X^{T}\right)}=\left\|\frac{1}{N^{S}} \sum_{i=1}^{N^{S}} \Phi\left(\mathrm{x}_{i}^{S}\right)-\frac{1}{N^{T}} \sum_{j=1}^{N^{T}} \Phi\left(\mathrm{x}_{j}^{T}\right)\right\|_{\mathcal{H}}^{2} eq. 2
\mathcal{L}_{c l s}=\sum_{i=1}^{N} \mathbf{E}_{x \sim X_{S}} J\left(\hat{\mathbf{Y}}_{i}^{S}, \mathbf{Y}_{i}^{S}\right) eq. 3
\mathcal{L}_{disc} = \sum_{i \neq j}^{N} \mathbf{E}_{x \sim X_{t}} \left|\hat{\textbf{Y}}_{i}^{T}-\hat{\textbf{Y}}_{j}^{T}\right| eq. 4
\mathcal{L} = \mathcal{L}_{cls} + \alpha \mathcal{L}_{mmd} + \beta \mathcal{L}_{disc} eq. 5
The paper uses a weight of 0.01 for the discrepancy term relative to α, applied over the whole training run tab. V §V-E. The α schedule is given in §V-A. Training uses the loop in Algorithm 1 alg. 1. The pseudocode below follows the paper's text and equations. The code differs in several places (see Paper vs code).
# Training loop of MS-MDA [alg. 1] [§IV]
# Input: N labelled source sets (X_i, Y_i) and one unlabelled target X_T
# Output: N branches; prediction = average of their softmax outputs
def train(sources, target, num_iterations, batch_size, lr):
# Build the shared extractor and one branch per source [§IV] [§V-A]
cfe = common_feature_extractor() # 310 -> 64
dsfe = [domain_specific_extractor() for _ in sources] # 64 -> 32
dsc = [linear(32, num_classes) for _ in sources] # 32 -> C
optimizer = adam(all_params, lr=lr) # lr 0.01 [§V-A]
for step in range(1, num_iterations + 1):
# Ramp the MMD weight alpha from 0 towards 1 [§V-A]
alpha = 2 / (1 + exp(-10 * step / num_iterations)) - 1
# Discrepancy weight is 0.01 times alpha [tab. V] [§V-E]
beta = 0.01 * alpha
# Draw m samples per source and m unlabelled target samples [alg. 1]
source_x, source_y = sample_per_source(sources, batch_size)
target_x = sample_target(target, batch_size)
# Common features for every domain [§IV] [alg. 1]
q_src = [cfe(x) for x in source_x]
q_tgt = cfe(target_x)
# Domain-specific features, one branch per source [§IV] [alg. 1]
r_src = [dsfe[i](q_src[i]) for i in range(num_sources)]
r_tgt = [dsfe[i](q_tgt) for i in range(num_sources)]
# MMD between each source branch and the target [eq. 2]
mmd = 0
for i in range(num_sources):
mmd += mmd_distance(r_src[i], r_tgt[i])
# Cross-entropy on each source branch [eq. 3]
cls = 0
for i in range(num_sources):
cls += cross_entropy(dsc[i](r_src[i]), source_y[i])
# Pairwise gap between the target predictions [eq. 4]
pred_tgt = [dsc[i](r_tgt[i]) for i in range(num_sources)]
disc = 0
for i in range(num_sources):
for j in range(num_sources):
if i != j:
disc += mean(abs(pred_tgt[i] - pred_tgt[j]))
# Total loss, then one gradient step [eq. 5] [alg. 1]
loss = cls + alpha * mmd + beta * disc
optimizer.zero_grad()
loss.backward()
optimizer.step()
# Inference: average the N branch predictions [§IV] [alg. 1]
def predict(x):
q = cfe(x) # (B, 64)
probs = []
for i in range(num_sources):
r = dsfe[i](q) # (B, 32)
probs.append(softmax(dsc[i](r))) # (B, C)
return mean(probs) # (B, C)Hyperparameters
| Name | Value | Where | Notes |
|---|---|---|---|
| Input features | 310 = 62 channels × 5 bands of DE | §III-D eq. 1 | DE features are supplied with the datasets; the text lists four band ranges but says five (see Pitfalls) |
| Samples per session | SEED 3394; SEED-IV 851 / 832 / 822 | §III-D | code uses 820 for SEED-IV (see Paper vs code) |
| CFE | 3-layer MLP, 310 → 64 | §IV §V-A | intermediate widths not stated; code uses 256 and 128 models.py |
| Activation (CFE, DSFE) | LeakyReLU | §V-A | negative slope not stated; code uses 0.01 models.py |
| DSFE | linear 64 → 32 + LeakyReLU | §IV §V-A | code adds BatchNorm1d before the LeakyReLU models.py |
| DSC | linear 32 → C, no activation | §V-A | C = 3 (SEED), 4 (SEED-IV) |
| Optimiser | Adam, initial lr 0.01 | §V-A | code keeps the lr constant; decay line is commented out msmdaer.py; betas not stated |
| Epochs | 200 | §V-A | code: iterations = ceil(epoch × 3394 / batch) for SEED msmdaer.py |
| Batch size | 256 samples per domain per iteration | §V-A | code default is 128 msmdaer.py |
| α schedule | 2 / (1 + e^(−10·i/epoch)) − 1 | §V-A | i is not defined in the text; code uses step / total iterations msmdaer.py |
| β (discrepancy weight) | 0.01 × α, whole training | tab. V §V-E | code: β = γ/100 msmdaer.py |
| MMD kernel | not stated beyond eq. 2 | eq. 2 | code uses a linear kernel utils.py |
| Normalisation | electrode-wise, before training | §V-D tab. IV | code normalises each of 310 feature columns msmdaer.py |
| Random seed | not stated | — | code sets seed 20 msmdaer.py |
| Subjects / sessions | 15 subjects, 3 sessions | §III-C | |
| Scenario split | cross-session: first 2 sessions as sources; cross-subject: first 14 subjects as sources | §III-B | code does leave-one-out (see Paper vs code) |
Results
Author-reported. Setup: SEED (15 subjects, 3 sessions, 3 classes) and SEED-IV (4 classes), DE features, shared-MLP model. Rows without a citation (DDC, DAN, DCORAL) were run by the authors with their settings; rows with a citation in tab. II are, per the text, copied from the original papers §V-B. Model size, hardware and training time are not stated. The ± values are standard deviations as described in §III-B. Accuracy in %.
| Dataset | Method | Cross-session | Cross-subject | Source |
|---|---|---|---|---|
| SEED | DDC | 81.53 ± 6.83 | 68.99 ± 3.23 | tab. II |
| SEED | DAN | 79.93 ± 7.06 | 65.84 ± 2.25 | tab. II |
| SEED | DAN [li2018cross] | - | 83.81 ± 8.56 | tab. II |
| SEED | DCORAL | 76.86 ± 7.61 | 66.29 ± 4.53 | tab. II |
| SEED | DANN [li2018cross] | - | 79.19 ± 13.14 | tab. II |
| SEED | PPDA [zhao2021plug] | - | 86.70 ± 7.10 | tab. II |
| SEED | MS-MDA (this paper) | 88.56 ± 7.80 | 89.63 ± 6.79 | tab. II |
| SEED-IV | DDC | 57.63 ± 11.28 | 37.41 ± 6.36 | tab. II |
| SEED-IV | DAN | 55.14 ± 12.79 | 32.44 ± 9.02 | tab. II |
| SEED-IV | DCORAL | 44.63 ± 11.38 | 37.43 ± 3.08 | tab. II |
| SEED-IV | MS-MDA (this paper) | 61.43 ± 15.71 | 59.34 ± 5.48 | tab. II |
The text says the margins are about 7% and 3% on SEED and about 7% and 18% on SEED-IV, for cross-session and cross-subject §V-B. Against the best baseline in tab. II, the SEED margins are 7.0 and 2.9 points. For SEED-IV the table gives 3.8 points (cross-session, against DDC) and 21.9 points (cross-subject, against DCORAL, the best of the three baselines there). The SEED-IV numbers in the text do not match the table.
Ablation (SEED and SEED-IV) tab. III
| Dataset | Method | Cross-session | Cross-subject |
|---|---|---|---|
| SEED | Full | 88.56 ± 7.80 | 89.63 ± 6.79 |
| SEED | w/o MMD loss | 82.20 ± 14.33 | 67.65 ± 17.65 |
| SEED | w/o disc. loss | 86.27 ± 9.14 | 87.27 ± 5.70 |
| SEED | w/o MMD + disc. loss | 83.19 ± 9.69 | 80.48 ± 5.76 |
| SEED-IV | Full | 61.43 ± 15.71 | 59.34 ± 5.48 |
| SEED-IV | w/o MMD loss | 56.51 ± 18.48 | 49.71 ± 5.82 |
| SEED-IV | w/o disc. loss | 61.63 ± 17.62 | 55.37 ± 14.38 |
| SEED-IV | w/o MMD + disc. loss | 62.66 ± 16.07 | 55.81 ± 4.17 |
On SEED-IV cross-session, the variant without both losses scores higher than the full model tab. III.
Normalisation study tab. IV
Three normalisations are compared: electrode-wise, sample-wise and global-wise fig. 4. Two orders are compared for DAN: normalise and then concatenate (order A, DAN¹) or concatenate and then normalise (order B, DAN²) fig. 5 §V-D.
| Model | Normalisation | SEED cross-session | SEED cross-subject | SEED-IV cross-session | SEED-IV cross-subject |
|---|---|---|---|---|---|
| DAN¹ | w/o normalisation | 33.96 ± 0.23 | 33.91 ± 0.09 | 27.23 ± 4.78 | 27.15 ± 1.31 |
| DAN¹ | electrode-wise | 79.93 ± 7.06 | 65.84 ± 2.25 | 55.14 ± 12.79 | 32.44 ± 9.02 |
| DAN¹ | sample-wise | 52.51 ± 11.92 | 51.77 ± 12.61 | 27.34 ± 2.45 | 32.03 ± 4.24 |
| DAN¹ | global-wise | 54.02 ± 9.29 | 49.12 ± 12.06 | 31.72 ± 6.46 | 29.31 ± 2.40 |
| DAN² | w/o normalisation | 33.96 ± 0.23 | 33.91 ± 0.09 | 27.23 ± 4.78 | 27.15 ± 1.31 |
| DAN² | electrode-wise | 79.78 ± 6.97 | 62.57 ± 5.31 | 52.18 ± 10.53 | 34.26 ± 7.98 |
| DAN² | sample-wise | 52.51 ± 11.92 | 51.77 ± 12.61 | 27.34 ± 2.45 | 32.03 ± 4.24 |
| DAN² | global-wise | 53.07 ± 10.50 | 50.22 ± 3.66 | 31.01 ± 7.56 | 31.77 ± 2.08 |
| MS-MDA | w/o normalisation | 80.62 ± 12.22 | 60.92 ± 3.58 | 30.11 ± 6.47 | 29.64 ± 7.26 |
| MS-MDA | electrode-wise | 86.94 ± 8.68 | 86.93 ± 8.24 | 64.07 ± 14.36 | 55.21 ± 6.30 |
| MS-MDA | sample-wise | 81.84 ± 13.72 | 74.09 ± 5.79 | 34.71 ± 10.94 | 30.25 ± 5.20 |
| MS-MDA | global-wise | 81.80 ± 12.75 | 78.89 ± 10.38 | 33.87 ± 10.99 | 31.88 ± 7.73 |
Discrepancy weight study tab. V
Training percentage 1 means the loss is used over the whole run, 0.2 means only the last 20% of training. Weight is the ratio to α tab. V caption. The first row has no discrepancy loss.
| Training % | Weight | SEED cross-session | SEED cross-subject | SEED-IV cross-session | SEED-IV cross-subject |
|---|---|---|---|---|---|
| w/o disc. | - | 86.27 ± 9.14 | 87.27 ± 5.70 | 61.63 ± 17.62 | 55.37 ± 14.38 |
| 0.2 | 1 | 86.94 ± 8.68 | 86.93 ± 8.24 | 64.07 ± 14.36 | 55.21 ± 6.30 |
| 0.2 | 0.1 | 86.99 ± 9.23 | 87.37 ± 7.64 | 64.75 ± 13.36 | 53.15 ± 11.88 |
| 0.2 | 0.01 | 86.87 ± 9.30 | 87.09 ± 8.02 | 64.04 ± 13.72 | 50.54 ± 15.59 |
| 0.2 | 0.001 | 86.91 ± 9.35 | 86.93 ± 8.24 | 64.14 ± 13.88 | 53.25 ± 9.55 |
| 1 | 1 | 85.58 ± 8.19 | 63.42 ± 2.15 | 61.88 ± 16.71 | 57.34 ± 9.07 |
| 1 | 0.1 | 85.80 ± 10.05 | 81.13 ± 11.19 | 62.42 ± 15.99 | 56.34 ± 10.18 |
| 1 | 0.01 | 88.56 ± 7.80 | 89.63 ± 6.79 | 61.43 ± 15.71 | 59.34 ± 5.48 |
| 1 | 0.001 | 86.36 ± 8.68 | 84.84 ± 3.49 | 64.41 ± 17.58 | 48.01 ± 8.66 |
The chosen setting (whole run, weight 0.01) is the one reported in tab. II §V-E.
Other experiments
- Batch size and epochs: both models drop as batch size grows; the drop is largest at batch 512 on SEED-IV. Longer training gives little gain, but MS-MDA converges faster §V-E fig. 6 fig. 7.
- t-SNE of raw, normalised, DAN-adapted and MS-MDA-adapted features, cross-subject case, target shown in black fig. 8 §V-E.
Paper vs code
Code: VoiceBeer/MS-MDA at commit a2946c38dc6b8d75e9a81bc1aa3651b1cb70f240
(MIT). The README notes that its LOSO runs differ from the paper's setup and
reports separate numbers for them README.md.
- Discrepancy term runs on the wrong tensors. The paper's eq. 4 uses the
classifier predictions Ŷᵀ. The code applies softmax to the 32-dimensional DSFE
features and takes the mean absolute difference, so classifiers are not
compared on their predictions. Paper: eq. 4. Code:
F.softmax(data_tgt_DSFE[...])models.py. The code averages over samples and classes. eq. 4 writes an absolute value with an expectation and does not say whether the class dimension is summed or averaged, so the scale may differ. - MMD kernel. The paper's eq. 2 is an RKHS distance. The code uses the
linear-kernel form
mmd_linear, which equals the squared distance between the two batch means utils.py. The Gaussian multi-kernel MMD is in the same file but commented out msmdaer.py. - Optimiser state and update schedule. The paper's Algorithm 1 does one update per iteration alg. 1. The code makes one optimiser step per source per iteration, and it creates a new Adam optimiser at the start of each iteration, which resets Adam's moments every iteration msmdaer.py msmdaer.py.
- Batch size default. The paper states 256 §V-A. The main script's default is 128 msmdaer.py. The ablation script's default is 256 msmdaer_wodisc.py.
- Number of iterations. The code computes iterations as ceil(epoch × sample count / batch), using 3394 for SEED and 820 for SEED-IV msmdaer.py. The paper gives 851, 832 and 822 samples for the three SEED-IV sessions §III-D.
- α schedule. The paper's i is undefined. The code uses the step index over the total number of iterations msmdaer.py. Paper: i/epoch §V-A.
- Learning rate. The paper gives an initial lr of 0.01 §V-A. The code keeps it constant; the decay formula is commented out msmdaer.py.
- DSFE has BatchNorm. The paper describes a linear layer and LeakyReLU §V-A. The code adds BatchNorm1d models.py.
- Source / target split. The paper says cross-session uses the first two sessions as sources and cross-subject uses the first 14 subjects §III-B. The code runs leave-one-out: every subject (cross-subject) and every session (cross-session) takes a turn as target msmdaer.py msmdaer.py msmdaer.py. That gives 45 runs per scenario, and the mean and std are taken over all 45 runs msmdaer.py. The paper says cross-session results are averaged over 15 subjects and cross-subject over 3 sessions §III-B.
- Normalisation. The paper calls the best method "electrode-wise" §V-D. The code min–max normalises each of the 310 feature columns separately, per subject and session matrix, before training msmdaer.py utils.py. Target data are included in these statistics.
- Test accuracy. The code evaluates the target set every 200 iterations and returns the highest accuracy seen msmdaer.py. The paper does not say how the reported checkpoint is chosen.
- Test batching. The target loader uses
drop_last=Trueand is also the loader used bytestmsmdaer.py msmdaer.py. Accuracy is divided by the full target size msmdaer.py, so the dropped samples count as errors. - Discrepancy weight in an extra script. The main script uses β = γ/100 msmdaer.py. The additions script uses γ/1000 msmdaer_additions.py.
- Baselines. The code includes separate DDC, DAN and DCORAL files DDC.py DAN.py DCORAL.py. The paper says some baseline numbers are copied from original papers §V-B.
No discrepancies found in the CFE linear layers (310 → 256 → 128 → 64), the DSC size, the Adam choice, or the 0.01 discrepancy ratio.
Pitfalls
- Discrepancy loss is the most fragile term. The text says it must be tuned carefully and can hurt when most classifiers are wrong §VI. Table V shows that its effect depends on the schedule and dataset. On SEED-IV cross-session the best row is 0.2 / 0.1 (64.75), not the chosen setting (61.43) tab. V.
- Hyperparameters were picked on the reported test numbers. The discrepancy weight is chosen from tab. V, which reports test accuracy on the same target sets §V-E. Normalisation is chosen the same way §V-D. Expect the headline numbers to be optimistic.
- Checkpoint selection on the target. The code returns the best checkpoint accuracy on target labels (see Paper vs code). Do not compare these numbers with methods that use a fixed stopping rule without saying so.
- Standard deviations are large. Several cells have ±10 or more on SEED-IV tab. II tab. III. Differences of 1 to 2 points are within noise. The paper does not state how many seeds were run.
- Cost grows with the number of sources. Every iteration passes the target through all N branches, and the authors report training time that grows linearly with N §VI. Cross-subject uses 14 sources and cross-session 2 §V-B.
- Band list is incomplete. The text lists four frequency bands but says there are five. The fifth range is not stated §III-D.
- Figure and table numbers. IEEE prints section and table numbers as Roman numerals and subsection letters, so this card cites them that way (for example §V-B, tab. II). Figure and equation numbers are arabic.
- Text margins do not match the table on SEED-IV (see Results).
- Unclear pieces that the code resolves differently or not at all: the MMD weight's ramp variable i, whether the MMD terms are summed over branches (the code does, by stepping through them), the LeakyReLU slope, the Adam betas, and the random seed.
Lineage
- Builds on: DAN (Long et al., 2015) and its MMD-based adaptation §II; the multi-source style transfer mapping of Li et al. (2019), which is similar but has no domain-invariant features §II; the multi-source aligning idea of Zhu et al. (2019), which motivates the one-to-one branches §II.
- Compared against: DDC, DAN, DCORAL, DANN and PPDA on SEED and SEED-IV tab. II.
- Superseded by: not known from the content of this wiki.
Source and license
Adapted from “MS-MDA: Multisource Marginal Distribution Adaptation for Cross-subject and Cross-session EEG Emotion Recognition” by Hao Chen, Ming Jin, Zhunan Li, Cunhang Fan, Jinpeng Li, Huiguang He (arXiv:2107.07740), used under CC BY 4.0. Changes: condensed and restructured for implementation, with tables, equations and algorithms taken from the paper and its code, each cited to its source. Not affiliated with or endorsed by the authors. Code citations refer to https://github.com/VoiceBeer/MS-MDA at commit a2946c38dc6b (MIT). Any quoted code is shown under that license.