InvCMNE
Namespace: INVLIB · Library: Inverse Library
#include <inv/inv_cmne.h>
class INVLIB::InvCMNE
Contextual Minimum Norm Estimate (CMNE) inverse solver.
Implements the algorithm from: Dinh et al. "Contextual Minimum-Norm Estimates (CMNE): A Deep Learning Method for Source Estimation in Neuroimaging", 2021.
CMNE inverse solver
// Contextual MNE: dSPM with a fixed-orientation kernel, then rectified and z-scored per source. Without an
// ONNX LSTM model the result is the paper's control estimate.
InvCMNESettings cmneSettings;
cmneSettings.lambda2 = lambda2;
cmneSettings.lookBack = 20;
const MatrixXd fixedGain = fixedFwd.sol->data;
const MatrixXd sourceCov = MatrixXd::Identity(fixedGain.cols(), fixedGain.cols());
const InvCMNEResult cmne = InvCMNE::compute(goodData, fixedGain, inverse.noise_cov->data, sourceCov, cmneSettings);
Static Methods
compute(matEvoked, matGain, matNoiseCov, matSrcCov, settings)
Compute CMNE inverse solution.
Parameters:
-
matEvoked : const Eigen::MatrixXd & Evoked data (n_channels x n_times).
-
matGain : const Eigen::MatrixXd & Forward gain matrix (n_channels x n_sources).
-
matNoiseCov : const Eigen::MatrixXd & Noise covariance (n_channels x n_channels).
-
matSrcCov : const Eigen::MatrixXd & Source covariance (n_sources x n_sources, diagonal).
-
settings : const InvCMNESettings & CMNE settings.
Returns:
- InvCMNEResult —
InvCMNEResultcontaining dSPM and CMNE source estimates.
applyCmne(matDspmData, onnxModelPath, sensing, prediction, cmne)
Contextual estimate of Eqs.
9-13, as cmne.apply_cmne with normalised weights.
The model must be exported by cmne.export_onnx: look-back, source count and rectification are read from its cmne_config metadata.
Parameters:
-
matDspmData : const Eigen::MatrixXd & Signed dSPM estimate (n_sources x n_times).
-
onnxModelPath : const QString & Path to the ONNX model.
-
sensing : Eigen::MatrixXd & q_t (Eq. 9).
-
prediction : Eigen::MatrixXd & LSTM prediction (q_t for the first k samples).
-
cmne : Eigen::MatrixXd & Contextual estimate b_t.
Returns:
- bool — False if the model cannot be loaded, does not fit the data, or there are no more than k samples.
controlEstimate(matDspmData, lookBack)
Control estimate of the paper (cmne.control_estimate): q_t times the mean of q over the previous lookBack samples, without an LSTM.
Parameters:
-
matDspmData : const Eigen::MatrixXd & Signed dSPM estimate (n_sources x n_times).
-
lookBack : int Window length k.
Returns:
- Eigen::MatrixXd — Control estimate (n_sources x n_times).
zScoreRectify(matStcData)
Rectify and z-score each source over time (Eq.
9).
Parameters:
- matStcData : const Eigen::MatrixXd & Source data (n_sources x n_times).
Returns:
- Eigen::MatrixXd — |x| standardised per row; constant rows are centred only.
trainLstm(fwdPath, covPath, epochsPath, outOnnxPath, settings, gtStcPrefix, hiddenSize, numLayers, trainEpochs, learningRate, batchSize, finetuneOnnxPath, pythonExe)
Train the CMNE LSTM model by invoking the Python training script.
This is a convenience wrapper that calls scripts/ml/training/train_cmne_lstm.py via PythonRunner. The heavy lifting (PyTorch LSTM training + ONNX export) happens in Python; C++ only launches the process and streams its output.
Parameters:
-
fwdPath : const QString & Path to forward solution FIFF file.
-
covPath : const QString & Path to noise covariance FIFF file.
-
epochsPath : const QString & Path to epochs FIFF file.
-
outOnnxPath : const QString & Desired output path for the ONNX model.
-
settings : const InvCMNESettings & CMNE settings (look-back, method, SNR are forwarded).
-
gtStcPrefix : const QString & Ground-truth STC prefix (optional; empty = simulation mode).
-
hiddenSize : int LSTM hidden dimension (default 256).
-
numLayers : int LSTM layers (default 1).
-
trainEpochs : int Number of training epochs (default 50).
-
learningRate : double Learning rate (default 1e-3).
-
batchSize : int Batch size (default 64).
-
finetuneOnnxPath : const QString & Existing ONNX model to fine-tune from (optional).
-
pythonExe : const QString & Python interpreter (default "python3").
Returns:
- PythonRunnerResult — PythonRunnerResult with exit code, captured output and progress.
Example
- Full source:
src/examples/ex_inv_api/main.cpp - Build target:
ex_inv_api(runs under CTest) - Data: mne-cpp-test-data
Used in examples
ex_inv_api
Inverse library: minimum-norm estimates, resolution matrices, label time courses, sparse solvers.
cmneSettings.lookBack = 20;
const MatrixXd fixedGain = fixedFwd.sol->data;
const MatrixXd sourceCov = MatrixXd::Identity(fixedGain.cols(), fixedGain.cols());
const InvCMNEResult cmne = InvCMNE::compute(goodData, fixedGain, inverse.noise_cov->data, sourceCov, cmneSettings);
// Every row of the dSPM kernel maps sensor noise with the noise covariance to unit variance.
const MatrixXd& kDspm = cmne.matKernelDspm;
const VectorXd unitNoise = (kDspm * inverse.noise_cov->data * kDspm.transpose()).diagonal();
ok &= expect(kDspm.rows() == 70 && (unitNoise.array() - 1.0).abs().maxCoeff() < 1e-6 && cmne.stcCmne.data.rows() == 70 && cmne.stcCmne.data.cols() == 421,
"InvCMNE: dSPM kernel has unit noise variance per source, CMNE estimate for all 421 samples");
Authors of this file
- Christoph Dinh <christoph.dinh@mne-cpp.org>