Repository navigation
BrainOmni: rotate with the released checkpoint's RoPE cache; keep the released head init - #1244
Conversation
…eep the released head init
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
RoPE cache expansion is not persisted, causing later short-sequence results to diverge from the released implementation.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Updates BrainOmni to match released checkpoint behavior and head initialization.
Changes:
- Loads and applies released RoPE buffers.
- Preserves default classification-head initialization.
- Adds parity and compatibility tests.
| File | Description |
|---|---|
braindecode/models/brainomni.py |
Implements checkpoint-compatible RoPE and head initialization. |
test/unit_tests/models/test_brainomni.py |
Adds parity and compatibility coverage. |
docs/whats_new.rst |
Documents the fixes. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #1244 +/- ##
=======================================
Coverage 88.53% 88.54%
=======================================
Files 158 158
Lines 19314 19330 +16
=======================================
+ Hits 17100 17116 +16
Misses 2214 2214 🚀 New features to boost your workflow:
|
# Conflicts: # docs/whats_new.rst
… dtype, as the release does
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Strict loading currently masks partially missing RoPE buffers, potentially producing silently inconsistent attention behavior.
Review effort: Balanced
Findings: 1
Open (1)
Resolved since last review (1)
…a partial RoPE state dict
…nit; note no attention dropout in eval
| "tokenizer.sensor_type", | ||
| }: | ||
| remapped[key] = own_state[key] | ||
| if not any(".rope_embedding_layer." in key for key in remapped): |
…nto feat/channel-layer



What changes
RoPE. The released BrainOmni checkpoints (
OpenTSLab/BrainOmni@9a4d3c70, tiny and base) storeblocks.*.time_attn.rope_embedding_layer.rotateas a float32 tensor of shape(240, n_dim/2). It holds the cosinescos(t·freqs)(max-abs 6e-8 from the exact values). The released downstream loader (downstream/model_collection/BrainOmni.py,load_state_dict(strict=False)) copies this tensor into the complex64rotatebuffer ofmodel_utils/attn.py::RotaryEmbedding. The sine part is therefore 0, and the released code rotates queries and keys with that cache. Every downstream sequence is shorter than 240 (Somato 2 s → 8 tokens), so all of them use the cached rotation.freqsis stored rounded to bfloat16 and is used only past 240 positions.The port dropped both keys and recomputed cos and sin. With this PR:
_RotaryPositionalEmbeddinghas the release'sfreqsandrotatebuffers.rotateis stored as the real view(seq, n_dim/2, 2)=(cos, sin), so it still runs in real arithmetic on devices without complex support.(seq, n_dim/2)cache is read as(cos, 0), which is what the release'scopy_into a complex buffer does.freqswith both cos and sin, as in the release's_set_rotate_cache..half()/.bfloat16(), like the release's complex64 cache under a bf16 engine.Head init.
final_layerkeeps PyTorch's defaultLinearinitialisation. The released head (downstream/model.py:Dropout → LazyLinear → SELU → Linear) is never passed through_init_weights, whichbrainomni/model.pyapplies only to the backbone.Numbers
Forward parity on identical inputs and identical released weights: 8 test segments of SomatoMotor (ds006035, 372 channels × 512 samples) prepared by the released maker. The released code is run verbatim (complex RoPE, CPU fp32) with attention dropout set to 0, because the release applies SDPA dropout in eval as well. Values are the max-abs difference per layer output:
encode(L2-normalised)All 11 blocks used by
encodeare 0 with this PR.In bf16 (both models cast with
.bfloat16()),encodediffers from the released code by 0.0586. The released code's own bf16 output differs from its fp32 output by 0.0597.Fine-tuning on SomatoMotor (372-channel input, BrainOmni tiny, the released downstream protocol on the same prepared segments and folds: 3 LRs × 5 subject folds × 2 seeds, best-val checkpoint tested, mean ± sd of test balanced accuracy at the LR with the best test mean, as in the released
metrics_stat.py):The paper reports 0.863 ± 0.128 for this cell. A full grid with this branch is running.
Not changed: the released attention applies
dropout_pin eval mode too. The port keeps eval deterministic (row "eval-mode attention dropout" above).Tests
test_spatial_temporal_block_matches_frozen_released_output: a seeded block whose RoPE buffers are in the released format, checked against values from the releasedSpatialTemporalAttentionBlockon the same state dict and input (offline).test_rope_rotates_with_the_released_cosine_only_cache(5 / 240 / 250 positions),test_rope_buffers_stay_float32_and_keep_dtype,test_brainomni_state_dict_without_rope_buffers_loads,test_brainomni_head_keeps_default_linear_init; the official-key load test now checks the converted cache.test_brainomni.py: 110 passed (network tests deselected locally).test_models/test_integration/test_return_features/test_model_contract/test_pretrained_compat/test_correctness/test_huggingface,-k brainomni: 19 passed, 1 skipped. pre-commit passes.