Skip to content

Add iEEG MAPA model - #1178

Merged
bruAristimunha merged 19 commits into
braindecode:masterfrom
julien-gadonneix:add-mapa-model
Oct 6, 2026
Merged

bruAristimunha merged 19 commits into
braindecode:masterfrom
julien-gadonneix:add-mapa-model

Conversation

@julien-gadonneix

@julien-gadonneix julien-gadonneix commented Sep 22, 2026 •

Copy link
Copy Markdown
Collaborator

Architecture verified against original codebase and paper.
Tests to load pretrained weights and reproduce results on the way.
Code style is still AI sloppy for now until validation tests :)

@codecov

codecov Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.38202% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.08%. Comparing base (5e00a5b) to head (2f9335b).
⚠️ Report is 2 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1178      +/-   ##
==========================================
+ Coverage   87.99%   88.08%   +0.09%     
==========================================
  Files         151      152       +1     
  Lines       17628    17895     +267     
==========================================
+ Hits        15511    15763     +252     
- Misses       2117     2132      +15     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

bruAristimunha and others added 5 commits September 25, 2026 00:31
- Turn the MAPA_DKT_REGIONS string into Sphinx #: comments (the bare
  string failed check-docstring-first) and keep the api.rst entry on one
  line (docstrfmt).
- License header is Apache-2.0, matching the upstream code it transcribes.
- Changelog cites this PR (braindecode#1178), not braindecode#1173.
- Docstring: window normalization is one of two numerical departures from
  the reference (the per-window STFT with reflect padding is the other);
  normalization="none" feeds the raw STFT magnitude, not the reference's
  inputs; pooling="flatten" reads the normed four-tap concatenation, not
  the paper's pre-norm block-12 read-out.
@julien-gadonneix
julien-gadonneix marked this pull request as ready for review September 28, 2026 16:53
Copilot AI lite review requested due to automatic review settings September 28, 2026 16:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Resolutions:
- NOTICE.txt: keep master's Apache-2.0 list (brant, diver1, mscformer) and
  the USC section, add the mapa.py line.
- docs/api.rst: keep both MAPA entries (foundation-model bullet and autosummary)
  next to master's MIRepNet/MSCFormer entries.
- docs/whats_new.rst: keep master's 1.8.1 section and place the :gh:`1178`
  MAPA entry first under Enhancements.
- test/unit_tests/models/test_return_features.py: keep both sides' params
  (MAPA after BIOT, master's Brant/BrainBERT/CBraMod kept).
- test/unit_tests/models/test_integration.py: auto-merged; master's
  _DIRECT_TORCHSCRIPT_MODELS count (32) kept — MAPA stays in
  not_working_models (torch.stft frontend), so the count does not change.
- braindecode/models/__init__.py, util.py, summary.csv: auto-merged.
- Fold the bespoke test/unit_tests/models/test_mapa.py into
  test_foundation_models.py under a "Tests for MAPA Model" section
  (maintainer convention: no per-model test files); tests renamed test_mapa_*.
- _token_layout cached the caller's sensor-indices tensor by reference,
  so an in-place edit of that tensor compared equal to the cached copy and
  returned a stale layout. Store a clone; covered by
  test_mapa_metadata_cache_owns_its_snapshot.
- Replace the private _rotate_half with braindecode.functional.rotate_pairs,
  which master added for the shared rotary code (bitwise identical).
- Header: link the upstream repository next to the Apache-2.0 notice, as
  LUNA/ZUNA do.
Master's generic test_reset_head_updates_config /
test_reset_head_model_reloads_after_saving require every model with a
custom reset_head to call _update_init_kwargs, otherwise from_config and
from_pretrained rebuild the old head size.
Copilot AI lite review requested due to automatic review settings September 30, 2026 07:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Resolutions:
- docs/whats_new.rst: master's file kept as is; the MAPA entry (:gh:`1178`)
  inserted first under Enhancements, above master's braindecode#1159 and braindecode#1155 entries.
A network-marked test downloads mapa_vits384.pt from the authors' Hub
repository at a pinned commit (sha256 equal to their GitHub release v0.1.0),
loads it with only the classification head missing, and compares the pooled
features of two deterministic raw windows, frontend included, with values
computed by the authors' code (bentang18/MAPA at bf2b49e).
Copilot AI lite review requested due to automatic review settings October 1, 2026 19:26
…n it

The reference values fit the authors' robust z-score on each window, as
the default normalization="window" does; the docstring now says so and
notes that CI's unit-test jobs do not pass --run-network.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Critical and moderate implementation issues remain unresolved in mapa.py.

Review effort: Lite
Findings: 2 High severity

Open (2)

Comment thread braindecode/models/mapa.py Outdated
Comment thread braindecode/models/mapa.py Outdated
Copilot AI lite review requested due to automatic review settings October 1, 2026 19:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Three moderate issues in mapa.py must be addressed before approval.

Review effort: Lite
Findings: 2 High severity

Open (2)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Frequency tensors remain on CPU for accelerator layouts

braindecode/​models/​mapa.py:978

When a non-default layout is built on an accelerator (for example, another subject or a different window length after model.to("cuda")), contact is on that device but exponents and the derived frequency tensors are created on CPU. The multiplications below then raise a device-mismatch error, breaking the documented dynamic montage/window support. Create the frequency schedule on contact.device.

Rewrite the class docstring in the layout of the other foundation models,
shorten the private helpers' docstrings, merge duplicated input checks, and
reuse rescale_parameter and FeedForwardBlock. FeedForwardBlock names its
layers 0-3, so a mapping renames the released checkpoint's mlp.fc1/fc2 keys
on load. Outputs and initialization are unchanged.

Co-authored-by: Cursor <[email protected]>
Copilot AI lite review requested due to automatic review settings October 2, 2026 01:35
@julien-gadonneix

Copy link
Copy Markdown
Collaborator Author

Note for the weights re-hosting step (7153879). The encoder's feed-forward blocks now use braindecode.modules.FeedForwardBlock, whose layers are named 0-3 instead of fc1/fc2. The authors' released mapa_vits384.pt (and its ablations) keeps the original names, so MAPA.mapping renames them on load:

encoder.blocks.{i}.mlp.fc1.{weight,bias} -> encoder.blocks.{i}.mlp.0.{weight,bias}
encoder.blocks.{i}.mlp.fc2.{weight,bias} -> encoder.blocks.{i}.mlp.3.{weight,bias}

This only applies through MAPA.load_state_dict. When re-hosting, either save MAPA(...).state_dict() after loading the original checkpoint (the keys then use the new names and the mapping is a no-op), or keep the original file and rely on the mapping. Checked: the original checkpoint loads with strict=False and only final_layer.{weight,bias} missing, and outputs and initialization are identical to before the change.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved moderate issues affect head resetting, configuration reconstruction, attention masking, and accelerator compatibility.

Review effort: Lite
Findings: 2 High severity · 1 Medium severity

Open (3)

Comment thread braindecode/models/mapa.py Outdated

@bruAristimunha bruAristimunha left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Julien, the port is in great shape. We reran the Neuroprobe Lite benchmark independently on Voyager (690/690 cells, seed 42): WithinSession 0.689 vs 0.695, CrossSession 0.685 vs 0.691, CrossSubject 0.607 vs 0.608 AUROC against the paper, with parity against the released checkpoint. The FeedForwardBlock reuse is behaviour-preserving (bit-identical logits), CI is green, pre-commit and tests pass. Approving.

@bruAristimunha bruAristimunha added model Adds a new model needs-replication Model PR: paper number must be replicated (NeuralBench) before merge labels Oct 5, 2026
julien-gadonneix and others added 2 commits October 5, 2026 15:25
…, strict sfreq, fix reset_head device/dtype and rotary device
# Conflicts:
#	docs/whats_new.rst
#	test/unit_tests/models/test_foundation_models.py
Copilot AI lite review requested due to automatic review settings October 5, 2026 13:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread braindecode/models/mapa.py
Comment thread braindecode/models/mapa.py
Comment thread braindecode/models/mapa.py
Comment thread braindecode/models/mapa.py
Comment thread braindecode/models/mapa.py
Comment thread braindecode/models/mapa.py
Comment thread braindecode/models/mapa.py
Copilot AI lite review requested due to automatic review settings October 5, 2026 15:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Comment thread braindecode/models/mapa.py
Comment thread braindecode/models/mapa.py
util.dkt_region_slots() now derives the 74-slot DKT region table from
mne.read_freesurfer_lut() ids at call time instead of typing out the
parcel/structure names: the 62 cortical parcels come from excluding five
DK ids (unknown, corpuscallosum, bankssts, frontalpole, temporalpole)
out of the contiguous 1000-1035 block and sorting what remains
alphabetically per hemisphere; the 12 subcortical slots come from the
six aseg ids in 10-18 that have a bilateral Right- counterpart. The one
piece that cannot be derived from MNE -- the released slot order of
those six aseg structures, which is neither ascending-id nor
alphabetical order -- is kept as a tiny position permutation, not a
name list, documented as sourced from the released checkpoint. A test
freezes the exact previously-hard-coded 74-name tuple and asserts the
new helper reproduces it exactly.
Copilot AI lite review requested due to automatic review settings October 5, 2026 19:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@bruAristimunha bruAristimunha left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Julien. Replication on Voyager: 690/690 Neuroprobe Lite cells within 0.007 AUROC of the paper (WithinSession 0.689 vs 0.695, CrossSession 0.685 vs 0.691, CrossSubject 0.607 vs 0.608), re-run on the simplified head with identical numbers; checkpoint parity 0.0. CI green.

@bruAristimunha
bruAristimunha merged commit 5d3c419 into braindecode:master Oct 6, 2026
19 of 24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

model Adds a new model needs-replication Model PR: paper number must be replicated (NeuralBench) before merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants