DeepReject Artifact Detection#
Overview#
DeepReject is the deep-learning-based artifact-detection branch used by
MEGFlow. The public configuration path is artifacts.deepreject. The
compatibility class is still named DeepRejectPredictor, but current
inference uses two independent final models rather than the earlier shared
two-head network:
BadChnNet predicts bad channels for the whole recording.
BadSegNet predicts bad time windows and converts them into MNE bad annotations.
Both models provide five bundled folds, and the default uses all five. DeepReject results are merged with the enabled PyPREP, PSD, OSL, and MNE detectors; they do not replace those detectors.
Execution Order#
For each preprocessed recording, MEGFlow performs the following operations:
Select data MEG channels. Reference MEG, stimulus, ECG, EOG, EMG, and miscellaneous channels are excluded when
pick_meg_onlyis true.Resolve
artifacts.deepreject.preprocand apply it to an isolated model input copy. The main Raw object and workflow FIF remain unchanged.When
run_bad_channelsis true, run BadChnNet and combine the selected fold predictions into one bad-channel decision per channel.When both models run, mask the BadChnNet channels in the recording passed to BadSegNet. If BadChnNet is disabled, BadSegNet receives the selected MEG channels without this model-derived mask.
When
run_bad_segmentsis true, run BadSegNet, average the selected fold window probabilities, and convert the probability sequence to bad intervals with hysteresis and interval post-processing.Merge the DeepReject bad channels and
BAD_deeprejectannotations with results from the other configured artifact detectors.Write the merged bad-channel and bad-segment sidecars together with a
deepreject_summary.jsonprovenance record.
BadChnNet#
For channel \(i\), let \(p_{f,i}\) be the predicted bad-channel probability from fold \(f\). MEGFlow calculates the fold mean and standard deviation:
The lower-confidence-bound score is
where badchnnet_lambda_lcb is \(\lambda\) and defaults to 1.0.
This penalizes channels whose predictions vary strongly across folds.
BadChnNet then derives a robust threshold separately for channel-name sensor
groups: Neuromag-style magnetometers, gradiometers, and a fallback group for
other naming schemes. A group receives its own threshold when it contains at
least badchnnet_min_type_channels channels. For LCB values \(x\) in a
sensor group,
A channel is bad when its LCB score is at least \(T\). Sensor types with too
few channels use the threshold computed from all channels. The default values
are floor=0.56, z=3.0, and min_type_channels=8.
BadSegNet#
For time window \(t\), BadSegNet averages the artifact probabilities from the selected folds:
Hysteresis converts this probability sequence into intervals. A candidate
component consists of consecutive windows with \(p_t\) at or above the low
threshold, and it is retained only if at least one window reaches the high
threshold. Candidate intervals separated by no more than
badsegnet_merge_gap_sec are merged. Intervals shorter than
badsegnet_min_duration_sec are removed unless their maximum probability
reaches badsegnet_short_keep_threshold.
The model window duration is read from the bundled fold configuration. Output
intervals are converted to seconds and written as BAD_deepreject MNE
annotations.
Modes#
mode changes BadSegNet post-processing only. It does not switch models,
change the input filter, or automatically select a mode from the MEG vendor.
Mode |
High |
Low |
Merge gap |
Minimum duration |
Short keep |
|---|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
strict generally marks more windows and retains weaker short intervals.
lenient retains only very high-confidence components and does not bridge
gaps. Explicit low-level values such as
badsegnet_hysteresis_high override the selected mode.
Configuration Fields#
Core controls#
Field |
Allowed values |
Docker default |
Meaning |
|---|---|---|---|
|
boolean |
|
Enables the DeepReject branch. |
|
|
|
Selects the BadSegNet post-processing preset. |
|
|
|
PyTorch inference device. |
|
|
|
Recording category. |
|
string or null |
inferred |
Optional provenance label. The input parent directory is used when omitted. |
|
boolean |
|
Runs BadChnNet. |
|
boolean |
|
Runs BadSegNet. At least one |
|
|
|
|
Input controls#
Field |
Type |
Default |
Meaning |
|---|---|---|---|
|
boolean |
|
Creates a temporary FIF containing data MEG channels only. |
|
boolean |
|
Excludes channels already present in |
|
boolean |
|
Keeps the temporary model-input FIF for debugging. |
|
operation list, |
model-validated recipe below |
Replaces the complete model-input recipe. Missing, null, or |
The explicit default recipe is:
params {
megflow {
defaults {
artifacts {
deepreject {
preproc = [
[filter: [l_freq: 1.0, h_freq: 100.0, method: "iir",
iir_params: [order: 5, ftype: "butter"]]],
[notch_filter: [freqs: 50]],
[resample: [sfreq: 250]]
]
}
}
}
}
}
Warning: A custom recipe or disabled preprocessing departs from the
model-validated default and may change inference behavior. A non-empty
preproc list replaces the whole recipe; it is not merged with the default.
DeepReject always applies an enabled recipe to a loaded copy and writes a
temporary prediction FIF, even when pick_meg_only is false. If a requested
frequency is not admissible at the source Nyquist rate but a later resample
target makes it admissible, resampling is performed first and the actual order
is recorded. Otherwise, only the inadmissible frequency part is skipped with a
reason. Upsampling runs normally, but it cannot recreate unavailable source
information. Narrow source bandwidth likewise does not stop inference and is
recorded as a source limitation.
deepreject_summary.json records source_before, recipe_source, the
resolved_recipe, actual applied_steps, model_input_after, whether
the recipe matches the default, and source_limitations. Each applied
resample also emits an INFO message stating that the main FIF is unchanged.
Inference and resource controls#
Field |
Type |
Default |
Meaning |
|---|---|---|---|
|
integer list or comma-separated string |
|
Ensemble folds to use. |
|
positive integer or |
|
Concurrent fold workers within one recording. |
|
boolean |
|
Keeps loaded fold models for repeated inference in the same process. |
|
positive integer or |
|
PyTorch CPU intra-operation threads per fold worker. |
|
positive integer |
|
PyTorch CPU inter-operation threads. MEGFlow fixes this value at one for artifact detection. |
|
positive integer |
|
BadSegNet inference batch size. |
|
positive integer or null |
null |
Optional encoder chunk size for memory-constrained runs. |
|
positive integer |
|
Number of graph neighbors used when constructing BadSegNet input. |
|
positive integer or null |
model config |
Number of windows in each BadChnNet recording chunk. |
|
positive integer or null |
model config |
Stride between BadChnNet chunks. |
|
positive integer or null |
model config |
Minimum number of windows retained in a final chunk. |
|
|
|
Combines multiple chunk predictions for one channel within a fold. |
The detect_artifacts process passes its assigned task.cpus into the
artifact runtime. Automatic allocation keeps
fold_workers * cpu_threads <= task.cpus while using the available budget:
4 CPUs resolve to 1 x 4, 8 to 2 x 4, 16 to 4 x 4, and 20 to
5 x 4. Larger budgets can increase the threads available to each fold.
Explicit worker and thread values are treated as preferences and are reduced
when their product would exceed the process budget. This controls PyTorch
parallelism separately from the single-thread native-library environment used
by the outer artifact process.
Post-processing controls#
Field |
Runtime default |
Meaning |
|---|---|---|
|
|
Probability required to activate a candidate bad interval. |
|
|
Probability required to continue the candidate interval. |
|
|
Maximum gap bridged between candidate intervals. |
|
|
Minimum interval duration after merging. |
|
|
Maximum probability that allows a short interval to bypass minimum duration removal. |
|
|
Fold-uncertainty penalty in the LCB score. |
|
|
Minimum bad-channel decision threshold. |
|
|
Robust MAD multiplier. |
|
|
Minimum channels required for a sensor-type-specific threshold. |
Common Configurations#
Use the calibrated defaults:
params {
megflow {
defaults {
artifacts {
deepreject {
enabled = true
mode = "default"
device = "cpu"
}
}
}
}
}
Use a conservative bad-segment policy for one dataset:
params {
megflow {
datasets {
MEG_MASC_word {
artifacts {
meg_vendor = "kit"
deepreject {
mode = "lenient"
}
}
}
}
}
}
Change only one task within a dataset:
params {
megflow {
defaults {
steps = "meg_artifacts"
}
datasets {
ExampleStudy {
recordings {
movement_task {
match {
task = "movement"
}
artifacts {
deepreject {
mode = "strict"
}
}
}
}
}
}
}
}
Outputs and Interpretation#
DeepReject contributes to these artifact outputs:
*_bad_channels.txt: merged final channel names from all enabled methods.*_bad_channels_description.json: detector provenance for each final bad channel, includingDeepReject BadChnNetwhen applicable.*_bad_segments.txt: merged MNE annotations; DeepReject intervals use the descriptionBAD_deepreject.deepreject_summary.json: selected folds, effective thresholds, input preprocessing, bad-channel probabilities, channel names, bad intervals, and runtime settings.check_imgs/artifact_mask_heatmap.jpg: recording-wide bad-channel and bad-time mask generated even when detailed artifact images are disabled.
An annotation marks a time range as bad; it does not remove samples from the continuous FIF. ICA and epoching decide whether to exclude marked samples. See Bad Segments: Marking vs Exclusion for downstream behavior.