DocsBCILattice Advanced Blocks
BCILattice Documentation

BCILattice Advanced Blocks

Complex Structures, Domain Adaptation, Domain Incremental Learning, and DL Training blocks available in the ML Suite (MLFlow) and Workflow Designer canvases.

v1.0BCINexus Platform · 2026-05-20[email protected]

Overview

New here? The Block Index lists every one of our blocks in a single line, grouped as the palette groups them.

Beyond the general-purpose Custom Blocks, BCILattice injects a much larger set of advanced structural and research blocks covering graph control flow, cross-subject/cross-session domain adaptation, continual (domain-incremental) learning, and full PyTorch-style deep-learning training primitives. These are the blocks that let the ML Suite and Workflow Designer express arbitrary research pipelines — branching, looping, ensembling, adapting between subjects, and training deep models — without writing code.

Like the blocks in the Custom Blocks reference, these are marked is_custom: true and run as server-side routines rather than catalog classes/functions. Click a block on the canvas and use the Documentation link in its property panel to jump straight back to the matching section below.

The block family at a glance

Counting the everyday palette blocks alongside the advanced ones, BCILattice declares and maintains 149 app-owned blocks across 15 categories. These are distinct from the ~11,300 catalog entries introspected out of third-party libraries: an app-owned block is code this application writes, tests and ships.

CategoryBlockscoreadvanced
DL Training431825
Training291217
Complex Structures12012
Evaluation1129
Pipeline Blocks844
Domain Adaptation844
Domain Incremental Learning808
Model Structure817
Media624
Preprocessing550
Analysis321
Reinforcement Learning303
Graph Learning202
Generative Models202
Inputs110

core blocks are the everyday ones — where a graph in that area usually starts; advanced ones answer more specialised questions. Every block is in the palette either way (the palette is chosen by library, not by tier). The split is a design-time declaration, not a runtime guess. Four blocks are additionally marked community and two legacy; both are counted under “advanced” above.

Engines and plan gates

146 of the 149 run on both engines — the ML Flow canvas and the Workflow Designer. The three exceptions are workflow-only by design: Select Files, Model Set and Sub-Workflow describe how a workflow is assembled rather than what a pipeline computes. Model Collection runs on both, and itsModels port carries into either canvas's trainers the same way.

148 of the 149 are free on every plan. The single gated block is Custom Code, which executes arbitrary Python you supply. Domain adaptation, continual learning, federated averaging, conformal prediction, NAS and the RL trainers are not upsells — they ship to everyone.

Why the count is trustworthy

A block on the canvas is not one artefact, it is five, and they live in five different files:

  1. a name constant
  2. a schema, which defines its ports and settings
  3. an executor branch that actually runs it
  4. a palette row, so it can be placed at all
  5. a test that runs it end to end

Nothing used to tie those five together, so a block could have four of them for months and still be impossible to place or impossible to run — which is exactly what happened to the eight Domain Adaptation blocks and the eight Domain Incremental ones, and independently to the DL Training optimizers, losses and schedulers.

A declaration a test can check

Every app-owned block is declared in one contract module, and a contract test probes the running server — the real executor dispatch and the real palette — rather than trusting the declaration. A block whose reality and declaration disagree fails the build in either direction: an undeclared block is as much a defect as an undelivered one. The allow-list of known-incomplete blocks is a shrink-only ratchet, and it currently stands at zero.

Complex Structures

Graph control-flow blocks: branching, merging, splitting, ensembling and looping. Available in both the ML Suite and Workflow Designer canvases. Ports on the "n_inputs / n_outputs" family of blocks below (Data Merger, Ensemble Voter, Feature Concatenator, Model Selector, Stacking Assembler, Data Splitter, Parallel Fan-out, Multi-Head Output, Pipeline Switch, Metrics Bundle) are dynamic — changing the corresponding count setting adds or removes numbered ports (1–12) on the block.

Conditional Branch

Complex StructuresML SuiteWorkflow DesignerFunction (custom)

Routes incoming data down one of two branches based on a condition evaluated against a value. Supports simple threshold/comparison modes as well as a free-form expression.

Inputs

Data:AnyCondition Value:Any

Outputs

Branch True:AnyBranch False:Any

Settings

SettingTypeDefaultDescription
conditionstrvalue > 0.5Expression evaluated when mode is "expression"
modeselectthresholdthreshold · equals · contains · greater · less · expression
thresholdfloat0.5—

Data Splitter

Complex StructuresML SuiteWorkflow DesignerFunction (custom)

Splits a single incoming array/dataset into 1–12 output splits by ratio, equal partition, or explicit index.

Inputs

Data:Any

Outputs

Split 1:AnySplit 2:Any… up to Split 12:Any

Settings

SettingTypeDefaultDescription
n_splitsint2Number of output splits (dynamic port count)
split_ratiosstr0.5,0.5Comma-separated ratios, used when strategy is "ratio"
axisint0—
strategyselectratioratio · equal · index
shuffleboolfalse—

Data Merger

Complex StructuresML SuiteWorkflow DesignerFunction (custom)

Combines 1–12 upstream data sources into one output using concatenation, stacking, or an elementwise reduction (mean/sum/max/min). The classic block for fusing multiple channels, sessions, or feature sets back into a single stream.

Inputs

Data 1:AnyData 2:AnyData 3:AnyData 4:Any… up to Data 12:Any

Outputs

Merged Data:Any

Settings

SettingTypeDefaultDescription
n_inputsint4Number of input ports (dynamic, 1–12)
axisint0—
methodselectconcatenateconcatenate · stack · mean · sum · max · min

Ensemble Voter

Complex StructuresML SuiteWorkflow DesignerFunction (custom)

Aggregates predictions from up to 12 models into one final prediction via majority vote, soft (probability-averaged) vote, weighted vote, or a stacking meta-combination. Also reports a confidence score.

Inputs

Predictions 1:AnyPredictions 2:AnyPredictions 3:Any… up to Predictions 12:Any

Outputs

Final Predictions:AnyConfidence:Any

Settings

SettingTypeDefaultDescription
n_inputsint4—
strategyselectsoftmajority · soft · weighted · stacking
weightsstr—Comma-separated weights, used when strategy is "weighted"
n_classesint0—

Pipeline Switch

Complex StructuresML SuiteWorkflow DesignerFunction (custom)

Routes data to one of up to 12 output routes based on a lookup of a config key against a case table — effectively a graph-level switch/case statement.

Inputs

Data:AnyConfig:Any

Outputs

Route 1:AnyRoute 2:Any… up to Route 12:Any

Settings

SettingTypeDefaultDescription
n_routesint3—
switch_keystrmodeKey read from Config to decide the route
default_routeselect11 · 2 · 3 · 4 · 5 · 6
casesstra->1,b->2,c->3value->route mapping

Parallel Fan-out

Complex StructuresML SuiteWorkflow DesignerFunction (custom)

Duplicates a single input into up to 12 identical output copies so the same data can feed several independent downstream branches.

Inputs

Data:Any

Outputs

Copy 1:AnyCopy 2:Any… up to Copy 12:Any

Settings

SettingTypeDefaultDescription
n_copiesint3—

Feature Concatenator

Complex StructuresML SuiteWorkflow DesignerFunction (custom)

Concatenates up to 12 feature vectors/arrays along a chosen axis, with an option to flatten every input first.

Inputs

Features 1:AnyFeatures 2:Any… up to Features 12:Any

Outputs

Concatenated Features:Any

Settings

SettingTypeDefaultDescription
n_inputsint5—
axisint-1—
flatten_allboolfalse—

Stacking Assembler

Complex StructuresML SuiteWorkflow DesignerFunction (custom)

Builds a stacked ensemble: trains a meta-learner on the out-of-fold predictions of up to 12 base models. Standard technique for squeezing extra accuracy out of several already-trained models.

Inputs

Base Model 1:AnyBase Model 2:Any… up to Base Model 12:AnyMeta Learner:Any

Outputs

Stacked Model:AnyOOF Predictions:Any

Settings

SettingTypeDefaultDescription
n_inputsint4—
cv_foldsint5—
use_probabooltrue—
passthroughboolfalseAlso feed original features to the meta-learner

Multi-Head Output

Complex StructuresML SuiteWorkflow DesignerFunction (custom)

Splits a shared feature trunk into up to 12 independent output heads, each with its own hidden size and activation — for multi-task models (e.g. predicting class + confidence + subject ID together).

Inputs

Features:Any

Outputs

Head 1 Output:AnyHead 2 Output:Any… up to Head 12 Output:Any

Settings

SettingTypeDefaultDescription
n_headsint3—
head_dimsstr128,64,32Comma-separated hidden size per head
activationselectrelurelu · tanh · sigmoid · none
dropoutfloat0—

ForEach

Complex StructuresML SuiteWorkflow DesignerFunction (custom)

Re-runs everything wired downstream of this block once per item in an incoming list (e.g. once per model in a Model Set, or once per hyperparameter combination). Each iteration binds item_var to the current item, so downstream blocks can reference it. Supports parallel workers, per-item timeouts, and stop-on-error or continue-on-error handling. Pair with ForEach Collect to rank the per-item results.

Inputs

Items:Any

Outputs

Output:AnySummary:Any

Settings

SettingTypeDefaultDescription
item_varstrmodelVariable name each downstream block can reference for the current item
on_errorselectstopstop · continue
body_workersint00 = sequential; >0 runs iterations concurrently
item_timeout_sfloat00 = no timeout

ForEach Collect

Complex StructuresML SuiteWorkflow DesignerFunction (custom)

Collects the per-iteration outputs of a ForEach loop, ranks them by a chosen metric key, and surfaces the best result plus a full comparison table.

Inputs

Items:Any

Outputs

Ranked:AnyBest:AnyTable:Any

Settings

SettingTypeDefaultDescription
metric_keystraccuracyKey inside each item used to rank results
sortselectdescdesc · asc

Workflow Structure

Workflow-only structural blocks for composing larger graphs out of existing experiments and already-published workflows.

Model Set

Workflow StructureWorkflow DesignerFunction (custom)

Selects one or more existing MLflow/Experiment Hub experiments and emits them as a list of items — designed to feed directly into a ForEach loop so you can, for example, run the same evaluation pipeline once per selected model.

Outputs

Items:Any

Settings

SettingTypeDefaultDescription
experiment_idsstr—Serialised list of chosen experiment IDs

Sub-Workflow

Workflow StructureWorkflow DesignerFunction (custom)

Embeds another workflow's compiled, published graph as a single reusable block. It always references the published snapshot — never the other workflow's live/in-progress canvas — so editing that other workflow later never silently changes a graph that already embeds it.

Outputs

Output:Any

Settings

SettingTypeDefaultDescription
workflow_namestr—Name of the published workflow to embed

Domain Adaptation

Blocks for aligning data or models across subjects, sessions, or recording devices — the core problem in BCI transfer learning, where a model trained on one subject/session often degrades on another.

MMD Aligner

Domain AdaptationML SuiteWorkflow DesignerFunction (custom)

Minimizes Maximum Mean Discrepancy between source and target feature distributions in a kernel space, reducing the statistical gap between two subjects/sessions before training.

Inputs

Source Data:AnyTarget Data:Any

Outputs

Aligned Data:AnyMMD Score:Any

Settings

SettingTypeDefaultDescription
kernelselectrbfrbf · linear · poly
n_componentsint64—
lambda_regfloat1—
bandwidthfloat1—

CORAL Adapter

Domain AdaptationML SuiteWorkflow DesignerFunction (custom)

Correlation Alignment: re-colors the source feature covariance to match the target's second-order statistics, a lightweight closed-form domain adaptation technique.

Inputs

Source Data:AnyTarget Data:Any

Outputs

Aligned Source:AnyAlignment Matrix:Any

Settings

SettingTypeDefaultDescription
lambda_regfloat1—

Transfer Component Analysis

Domain AdaptationML SuiteWorkflow DesignerFunction (custom)

Learns a shared low-dimensional projection where source and target distributions become similar, using kernel-based transfer components (TCA).

Inputs

Source Data:AnyTarget Data:Any

Outputs

Source Projected:AnyTarget Projected:Any

Settings

SettingTypeDefaultDescription
n_componentsint30—
mufloat1—
kernelselectrbfrbf · linear · poly
gammafloat1—

DANN Discriminator

Domain AdaptationML SuiteWorkflow DesignerFunction (custom)

Domain-Adversarial Neural Network discriminator: a gradient-reversal classifier trained to fail at telling source and target features apart, forcing the upstream feature extractor to learn domain-invariant representations.

Inputs

Features:Any

Outputs

Domain Predictions:AnyGradient Reversed:Any

Settings

SettingTypeDefaultDescription
hidden_dimint256—
n_layersint2—
lambda_grlfloat1Gradient reversal strength
dropoutfloat0.5—

Feature Alignment

Domain AdaptationML SuiteWorkflow DesignerFunction (custom)

Simple statistical feature alignment (z-score, whitening, centering, Procrustes, or affine) between source and target — a fast baseline before reaching for MMD/CORAL/DANN.

Inputs

Source Data:AnyTarget Data:Any

Outputs

Aligned Data:Any

Settings

SettingTypeDefaultDescription
methodselectz-scorez-score · whitening · centering · procrustes · affine
n_componentsint0—

Subject Adaptation

Domain AdaptationML SuiteWorkflow DesignerFunction (custom)

Adapts a base model to a new subject using a small amount of that subject's calibration data, picking from several adaptation strategies (fine-tuning, DANN, TCA, Euclidean alignment, or CORAL).

Inputs

Base Model:AnyAdaptation Data:AnyAdaptation Labels:Any

Outputs

Adapted Model:AnyAdaptation Score:Any

Settings

SettingTypeDefaultDescription
methodselectfine-tunefine-tune · DANN · TCA · euclidean-alignment · CORAL
epochsint10—
lrfloat0.0001—
n_shotsint20Number of calibration samples used
deviceselectautoauto · cpu · cuda

Euclidean Alignment

Domain AdaptationML SuiteWorkflow DesignerFunction (custom)

Whitens trial covariance matrices toward a reference (mean/median/first trial), a fast and widely used EEG-specific alignment technique that requires no labels.

Inputs

Data:AnyReference:Any

Outputs

Aligned Data:AnyReference:AnyAdaptation Report:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
reference_modeselectmeanmean · median · first

Session Transfer

Domain AdaptationML SuiteWorkflow DesignerFunction (custom)

Transfers features across recording sessions of the same or different subjects via reweighting, projection, normalization, or optimal transport, and outputs per-sample importance weights alongside the transferred features.

Inputs

Source Features:AnyTarget Features:AnySource Labels:Any

Outputs

Transferred Features:AnySample Weights:Any

Settings

SettingTypeDefaultDescription
methodselectprojectionreweighting · projection · normalization · optimal-transport
n_componentsint0—

Domain Incremental Learning

Continual-learning blocks that let a model keep learning from new subjects/sessions/tasks over time without catastrophically forgetting what it already knew.

EWC Regularizer

Domain Incremental LearningML SuiteWorkflow DesignerFunction (custom)

Elastic Weight Consolidation: penalizes changes to parameters that were important for previous tasks, estimated via the Fisher information matrix, so the model resists forgetting while learning a new task.

Inputs

Model:AnyPrevious Task Data:Any

Outputs

Regularized Model:AnyFisher Matrix:Any

Settings

SettingTypeDefaultDescription
lambda_ewcfloat400Strength of the consolidation penalty
fisher_samplesint200—
consolidate_everyint1—
onlineboolfalseUse Online EWC (single accumulated penalty) instead of per-task terms
gammafloat1—

Replay Buffer

Domain Incremental LearningML SuiteWorkflow DesignerFunction (custom)

Maintains a fixed-size memory of past examples (random, herding, exemplar, or gradient-based selection) that can be replayed alongside new data to reduce forgetting.

Inputs

New Data:AnyNew Labels:Any

Outputs

Buffered Data:AnyBuffered Labels:Any

Settings

SettingTypeDefaultDescription
buffer_sizeint500—
strategyselectrandomrandom · herding · exemplar · gradient
n_classesint4—
update_policyselectreservoirreservoir · ring · fifo

Task Manager

Domain Incremental LearningML SuiteWorkflow DesignerFunction (custom)

Maintains a set of per-domain/per-task output heads on top of a shared model and routes each sample to the right head, either from a known domain ID or inferred via entropy/prototype matching.

Inputs

Model:AnyDomain ID:AnyTask Labels:Any

Outputs

Task Model:AnyTask Head:Any

Settings

SettingTypeDefaultDescription
n_domainsint5—
head_typeselectlinearlinear · mlp · attention
shared_layersint-2Number of trunk layers shared across tasks
task_inferenceselectknownknown · entropy · prototype

PackNet Freezer

Domain Incremental LearningML SuiteWorkflow DesignerFunction (custom)

Implements PackNet-style continual learning: prunes a fraction of a model's weights, retrains the pruned subnetwork on a new task, and freezes it, packing multiple tasks into disjoint weight subsets of one network.

Inputs

Model:Any

Outputs

Packed Model:AnyFrozen Mask:Any

Settings

SettingTypeDefaultDescription
prune_ratiofloat0.5—
task_idint0—
retrain_epochsint5—

Progressive Layers

Domain Incremental LearningML SuiteWorkflow DesignerFunction (custom)

Expands a base model with new units/layers for a new domain while freezing the original network and adding lateral connections back to it, following the Progressive Neural Networks approach.

Inputs

Base Model:AnyNew Domain Data:Any

Outputs

Expanded Model:Any

Settings

SettingTypeDefaultDescription
n_new_unitsint64—
lateral_connectionsbooltrue—
freeze_previousbooltrue—
n_layers_to_expandint1—

Domain Drift Detector

Domain Incremental LearningML SuiteWorkflow DesignerFunction (custom)

Monitors incoming data for statistical drift relative to a reference distribution (MMD, KS-test, covariate shift, ADWIN, or Page-Hinkley), flagging when it's time to trigger adaptation or retraining.

Inputs

Reference Data:AnyCurrent Data:Any

Outputs

Drift Score:AnyIs Drifted:Any

Settings

SettingTypeDefaultDescription
methodselectmmdmmd · ks-test · covariate-shift · adwin · page-hinkley
thresholdfloat0.05—
window_sizeint100—
alphafloat0.05—

DL Training

A full set of PyTorch-backed deep-learning primitives — optimizers, loss functions, LR schedulers, data loading, metrics, and a trainer block — so deep models can be assembled and trained entirely on the canvas.

Optimizers

Every optimizer block takes a Model input and produces an Optimizer output to wire into BCILattice Trainer.

Adam Optimizer

DL Training · OptimizerML SuiteWorkflow DesignerFunction (custom)

Adaptive moment estimation — maintains per-parameter running averages of the gradient and its square. The default choice for most DL Training pipelines.

Inputs

Model:Any

Outputs

Optimizer:Any

Settings

SettingTypeDefaultDescription
lrfloat0.001Learning rate
beta1float0.9Exponential decay rate for the 1st moment estimate
beta2float0.999Exponential decay rate for the 2nd moment estimate
epsfloat1e-8Numerical stability term
weight_decayfloat0L2 penalty coefficient
amsgradboolfalseUse the AMSGrad variant

AdamW Optimizer

DL Training · OptimizerML SuiteWorkflow DesignerFunction (custom)

Adam with decoupled weight decay — the decay term is applied directly to the weights instead of being folded into the gradient, which generalizes better for large models.

Inputs

Model:Any

Outputs

Optimizer:Any

Settings

SettingTypeDefaultDescription
lrfloat0.001—
beta1float0.9—
beta2float0.999—
epsfloat1e-8—
weight_decayfloat0.01Decoupled L2 penalty (higher default than Adam)

SGD Optimizer

DL Training · OptimizerML SuiteWorkflow DesignerFunction (custom)

Stochastic gradient descent with momentum and optional Nesterov acceleration. Slower to converge than Adam variants but often generalizes better on smaller EEG/fNIRS datasets.

Inputs

Model:Any

Outputs

Optimizer:Any

Settings

SettingTypeDefaultDescription
lrfloat0.01—
momentumfloat0.9—
weight_decayfloat0—
nesterovbooltrueUse Nesterov momentum
dampeningfloat0—

RMSprop Optimizer

DL Training · OptimizerML SuiteWorkflow DesignerFunction (custom)

Divides the learning rate by a running average of recent gradient magnitudes. Well suited to recurrent/sequence models.

Inputs

Model:Any

Outputs

Optimizer:Any

Settings

SettingTypeDefaultDescription
lrfloat0.01—
alphafloat0.99Smoothing constant
epsfloat1e-8—
weight_decayfloat0—
momentumfloat0—

Adamax Optimizer

DL Training · OptimizerML SuiteWorkflow DesignerFunction (custom)

Adam variant based on the infinity norm, which is more stable with sparse gradients or embeddings.

Inputs

Model:Any

Outputs

Optimizer:Any

Settings

SettingTypeDefaultDescription
lrfloat0.002—
beta1float0.9—
beta2float0.999—
epsfloat1e-8—
weight_decayfloat0—

NAdam Optimizer

DL Training · OptimizerML SuiteWorkflow DesignerFunction (custom)

Adam with Nesterov momentum baked into the moment update, often converging slightly faster than plain Adam.

Inputs

Model:Any

Outputs

Optimizer:Any

Settings

SettingTypeDefaultDescription
lrfloat0.002—
beta1float0.9—
beta2float0.999—
epsfloat1e-8—
weight_decayfloat0—

Loss Functions

Loss blocks take no data inputs — they configure and emit a Loss Fn to wire into BCILattice Trainer.

CrossEntropy Loss

DL Training · LossML SuiteWorkflow DesignerFunction (custom)

Standard multi-class classification loss; combines log-softmax and negative log-likelihood in one block.

Outputs

Loss Fn:Any

Settings

SettingTypeDefaultDescription
label_smoothingfloat0Smooths hard 0/1 targets toward uniform
reductionselectmeanmean · sum · none
ignore_indexint-1Target value excluded from the loss

BCE Loss

DL Training · LossML SuiteWorkflow DesignerFunction (custom)

Binary cross-entropy for two-class problems, expects the model output already passed through a sigmoid.

Outputs

Loss Fn:Any

Settings

SettingTypeDefaultDescription
reductionselectmeanmean · sum · none

BCEWithLogits Loss

DL Training · LossML SuiteWorkflow DesignerFunction (custom)

Numerically stable binary cross-entropy that applies the sigmoid internally — use this instead of BCE Loss whenever the model outputs raw logits.

Outputs

Loss Fn:Any

Settings

SettingTypeDefaultDescription
reductionselectmeanmean · sum · none
pos_weightfloat1Up-weights the positive class for imbalanced data

MSE Loss

DL Training · LossML SuiteWorkflow DesignerFunction (custom)

Mean squared error for continuous-target regression tasks (e.g. predicting a continuous BCI control signal).

Outputs

Loss Fn:Any

Settings

SettingTypeDefaultDescription
reductionselectmeanmean · sum · none

L1 Loss

DL Training · LossML SuiteWorkflow DesignerFunction (custom)

Mean absolute error — less sensitive to outliers than MSE, at the cost of a non-smooth gradient at zero.

Outputs

Loss Fn:Any

Settings

SettingTypeDefaultDescription
reductionselectmeanmean · sum · none

Huber Loss

DL Training · LossML SuiteWorkflow DesignerFunction (custom)

Quadratic near zero and linear beyond a threshold — a robust middle ground between MSE and L1 for noisy regression targets.

Outputs

Loss Fn:Any

Settings

SettingTypeDefaultDescription
reductionselectmeanmean · sum · none
deltafloat1Threshold where the loss switches from quadratic to linear

NLL Loss

DL Training · LossML SuiteWorkflow DesignerFunction (custom)

Negative log-likelihood loss for use when the model already outputs log-probabilities (e.g. after a manual log-softmax).

Outputs

Loss Fn:Any

Settings

SettingTypeDefaultDescription
reductionselectmeanmean · sum · none
ignore_indexint-1—

Focal Loss

DL Training · LossML SuiteWorkflow DesignerFunction (custom)

Down-weights easy, well-classified examples so training focuses on hard/rare examples — useful for imbalanced class distributions common in BCI event detection.

Outputs

Loss Fn:Any

Settings

SettingTypeDefaultDescription
alphafloat0.25Balances the positive/negative class contribution
gammafloat2Focusing parameter; higher values down-weight easy examples more
reductionselectmeanmean · sum · none

LR Schedulers

Scheduler blocks wrap an incoming Optimizer and pass it through alongside the new Scheduler.

StepLR

DL Training · SchedulerML SuiteWorkflow DesignerFunction (custom)

Decays the learning rate by a fixed factor every N epochs.

Inputs

Optimizer:Any

Outputs

Scheduler:AnyOptimizer:Any

Settings

SettingTypeDefaultDescription
step_sizeint10Epochs between each decay step
gammafloat0.1Multiplicative decay factor

CosineAnnealingLR

DL Training · SchedulerML SuiteWorkflow DesignerFunction (custom)

Smoothly anneals the learning rate along a cosine curve down to eta_min over T_max epochs.

Inputs

Optimizer:Any

Outputs

Scheduler:AnyOptimizer:Any

Settings

SettingTypeDefaultDescription
T_maxint50Number of epochs for one full cosine cycle
eta_minfloat0Minimum learning rate

ReduceLROnPlateau

DL Training · SchedulerML SuiteWorkflow DesignerFunction (custom)

Reduces the learning rate when a monitored metric stops improving — the standard choice when you do not know a good decay schedule in advance.

Inputs

Optimizer:Any

Outputs

Scheduler:AnyOptimizer:Any

Settings

SettingTypeDefaultDescription
modeselectminmin · max
factorfloat0.1—
patienceint10Epochs to wait before reducing
thresholdfloat0.0001—
min_lrfloat0—

OneCycleLR

DL Training · SchedulerML SuiteWorkflow DesignerFunction (custom)

Ramps the learning rate up then back down within a single training run, often enabling faster convergence ("super-convergence").

Inputs

Optimizer:Any

Outputs

Scheduler:AnyOptimizer:Any

Settings

SettingTypeDefaultDescription
max_lrfloat0.01—
steps_per_epochint100—
epochsint10—
pct_startfloat0.3Fraction of the cycle spent increasing the LR

ExponentialLR

DL Training · SchedulerML SuiteWorkflow DesignerFunction (custom)

Decays the learning rate by a constant multiplicative factor every epoch.

Inputs

Optimizer:Any

Outputs

Scheduler:AnyOptimizer:Any

Settings

SettingTypeDefaultDescription
gammafloat0.95Per-epoch decay factor

CyclicLR

DL Training · SchedulerML SuiteWorkflow DesignerFunction (custom)

Cycles the learning rate between a lower and upper bound, which can help escape saddle points during training.

Inputs

Optimizer:Any

Outputs

Scheduler:AnyOptimizer:Any

Settings

SettingTypeDefaultDescription
base_lrfloat0.001—
max_lrfloat0.01—
step_size_upint2000—
modeselecttriangulartriangular · triangular2 · exp_range

CosineWarmRestarts

DL Training · SchedulerML SuiteWorkflow DesignerFunction (custom)

Cosine annealing with periodic warm restarts — the cycle length can grow by T_mult after each restart.

Inputs

Optimizer:Any

Outputs

Scheduler:AnyOptimizer:Any

Settings

SettingTypeDefaultDescription
T_0int10Epochs until the first restart
T_multint2Cycle-length multiplier after each restart
eta_minfloat0—

PyTorch DataLoader

DL TrainingML SuiteWorkflow DesignerFunction (custom)

Wraps a dataset in a PyTorch DataLoader with batching, shuffling, worker processes, and pinned memory — the standard entry point for feeding batched data into a deep-learning training run.

Inputs

Dataset:Any

Outputs

DataLoader:Any

Settings

SettingTypeDefaultDescription
batch_sizeint32—
shufflebooltrue—
num_workersint0—
pin_memoryboolfalse—
drop_lastboolfalse—
prefetch_factorint2—

Train/Val Splitter

DL TrainingML SuiteWorkflow DesignerFunction (custom)

Splits a dataset into train and validation sets using a random, stratified, subject-wise, session-wise, or leave-one-subject-out policy — important for BCI data where naive random splits leak subject identity between train and val.

Inputs

Dataset:Any

Outputs

Train Dataset:AnyVal Dataset:AnySplit Manifest:Any

Settings

SettingTypeDefaultDescription
val_splitfloat0.2—
seedint42—
stratifyboolfalse—
split_policyselectrandomrandom · stratified · subject_wise · session_wise · leave_one_subject_out

Metric Calculator

DL TrainingML SuiteWorkflow DesignerFunction (custom)

Turns predictions and true labels into numbers, on the canvas. Wire Predictions and True Labels (Evaluate Model emits both under those names) and it computes accuracy, F1, precision, recall and the confusion matrix — no metric blocks required. Wire Probabilities too and it adds ROC AUC and Log Loss, which are the only two metrics that need them. Everything lands on one Metrics port as a single {name: value} dict, so an Output Block wired to it reports every metric by name rather than one number, and the Execute page picks the whole set up whether or not you wire the output at all. For finer control, connect individual metric blocks, a Metrics Bundle or a Standard Metrics preset into any Metric N port and those are used instead.

Inputs

Predictions:AnyTrue Labels:AnyProbabilities:AnyMetric 1:Any… up to Metric 12:Any

Outputs

Metrics:AnyMetric Names:AnySkipped:AnyReport:Any

Settings

SettingTypeDefaultDescription
presetselectautoauto: use the metric blocks you wired if there are any, otherwise the standard set — extended with ROC AUC and Log Loss when Probabilities is connected. wired: use only the connected metric blocks.
n_metricsint4How many Metric N ports the node shows (1–12)
prefixstr—Prefixes every metric name, so two calculators in one graph land as separate rows instead of overwriting each other
averageselectweightedAveraging for F1 / precision / recall when the preset supplies them
multi_classselectovrovr · ovo
normalizeselectnonenone · true · pred · all
print_in_terminalbooltruePrint the confusion matrix to the run log

Nothing is dropped silently. A metric the calculator could not compute is named in Report and on the Skipped port. If you explicitly wired a ROC AUC Metric or Log Loss Metric block and left Probabilities empty, the run stops with an error instead — you asked for that metric by placing the node, so its absence is a mistake rather than a preference.

The Metrics dict also carries an evaluation_protocol entry — the number of scored rows, the class balance, the majority-class baseline and a confidence interval on accuracy. It deliberately does not carry a split_policy: this block scores the arrays handed to it and has no splitter of its own, so it never labels your numbers with another node's split.

Standard Metrics

DL TrainingML SuiteWorkflow DesignerFunction (custom)

The whole metric suite as one node. Pick a preset and wire its Metrics output into BCILattice Trainer's Metrics port — or into a Metric Calculator — instead of placing seven metric blocks and a Metrics Bundle every time. It emits exactly the configs those blocks would have, so nothing downstream can tell the difference; place the individual blocks when you need two different averages for two different metrics.

Outputs

Metrics:AnyMetric Names:AnyReport:Any

Settings

SettingTypeDefaultDescription
presetselectstandardstandard: accuracy, F1, precision, recall, confusion matrix — everything computable from predictions alone. probabilistic / everything: adds ROC AUC and Log Loss, which need per-class probabilities.
averageselectweightedweighted · macro · micro · binary · samples
multi_classselectovrovr · ovo
normalizeselectnonenone · true · pred · all
print_in_terminalbooltrue—

Metric Blocks

Each metric block takes no inputs and emits a single Metric output — aspecification of a metric, not the metric itself. Wire one into Metric Calculator to compute it on a set of predictions, or into BCILattice Trainer (directly, or via Metrics Bundle) to track it during training. If you just want the usual set, reach for Standard Metrics instead of placing all seven.

Accuracy Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Fraction of predictions that exactly match the true label. No configurable settings.

Outputs

Metric:Any

F1 Score Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Harmonic mean of precision and recall — a better single-number summary than accuracy for imbalanced classes.

Outputs

Metric:Any

Settings

SettingTypeDefaultDescription
averageselectweightedweighted · macro · micro · binary · samples

Precision Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Of everything predicted positive, the fraction that was actually positive.

Outputs

Metric:Any

Settings

SettingTypeDefaultDescription
averageselectweightedweighted · macro · micro · binary · samples

Recall Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Of everything actually positive, the fraction the model correctly found.

Outputs

Metric:Any

Settings

SettingTypeDefaultDescription
averageselectweightedweighted · macro · micro · binary · samples

ROC AUC Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Area under the ROC curve — threshold-independent measure of separability between classes.

Outputs

Metric:Any

Settings

SettingTypeDefaultDescription
averageselectmacromacro · weighted · micro · samples
multi_classselectovrovr · ovo

Confusion Matrix Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Full per-class prediction breakdown, optionally normalized and printed to the training log.

Outputs

Metric:Any

Settings

SettingTypeDefaultDescription
normalizeselectnonenone · true · pred · all
print_in_terminalbooltrue—

Log Loss Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Cross-entropy of the predicted class probabilities against the true labels — penalizes confident wrong predictions heavily.

Outputs

Metric:Any

Settings

SettingTypeDefaultDescription
epsfloat1e-15Clipping bound to avoid log(0)

R2 Score Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Regression. How much of the target's variance the model explains: 1 is perfect, 0 is no better than always predicting the mean, and it can go negative.

Outputs

Metric:Any

MAE Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Regression. Mean absolute error — the average distance between prediction and truth, in the target's own units.

Outputs

Metric:Any

MSE Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Regression. Mean squared error — like MAE but squares each error first, so large misses count much more.

Outputs

Metric:Any

RMSE Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Regression. Root mean squared error — MSE brought back to the target's units, so it reads like MAE but still punishes large misses.

Outputs

Metric:Any

Median AE Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Regression. Median absolute error — the typical miss, unaffected by a few very bad predictions.

Outputs

Metric:Any

MAPE Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Regression. Mean absolute percentage error — the average miss as a share of the true value. Misleading when true values are near zero.

Outputs

Metric:Any

Explained Variance Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Regression. Like R², but ignores a constant offset between prediction and truth — a biased model can score well here and worse on R².

Outputs

Metric:Any

Pearson Correlation Metric

DL Training · MetricML SuiteWorkflow DesignerFunction (custom)

Regression. Whether predictions rise and fall with the truth (−1 to 1), regardless of scale or offset. A high correlation can still come with large errors.

Outputs

Metric:Any

What the trainer can compute, and what it can't. Metric blocks wired into BCILattice Trainer reach the training backend as metric ids, and the backends differ: the scikit-learn backend computes accuracy, balanced accuracy, F1, precision and recall; the PyTorch backend computes accuracy. ROC AUC, Log Loss and the confusion matrix are declined there by name — use Metric Calculator on the trainer's predictions to get them.

Metrics Bundle

DL TrainingML SuiteWorkflow DesignerFunction (custom)

Bundles 1–12 individual metric blocks into a single Metrics output for BCILattice Trainer, so multiple metrics (accuracy, F1, ROC AUC, …) can be tracked from one training run.

Inputs

Metric 1:AnyMetric 2:Any… up to Metric 12:Any

Outputs

Metrics:Any

Settings

SettingTypeDefaultDescription
n_inputsint6—

BCILattice Trainer

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

The plain supervised trainer, and the one to reach for. It covers both classical ML and deep learning behind one node: wire a Dataset, a Model and Labels, and it handles the split, the training loop and the evaluation. Leave Validation empty for one hold-out split; wire a Validation Scheme into it to cross-validate, or an Evaluation Protocol to choose which sessions or subjects train and which test. Other kinds of training (fine-tuning, DANN, contrastive, multi-task, incremental, distillation) are separate trainer blocks, listed below. Optimizer and loss default to 'auto' and are chosen from the model and task, so a working pipeline needs no optimizer/loss/dataloader wiring at all.

Inputs

Dataset:AnyModel:AnyLabels:AnyVal/Eval:AnyAdditional Metrics:AnyCallbacks:Any

Outputs

Trained Model:AnyMetrics:AnyTraining History:AnyProvenance:AnyLogs:AnyTest Labels:AnyTest Predictions:AnyTest Probabilities:AnyFold Scores:AnyCV Report:Any

Settings

SettingTypeDefaultDescription
task_typeselectautoauto infers from the labels
split_strategyselectautoUse subject_wise or leave_one_subject_out for a result that generalises across people — a random split over multi-subject data leaks subject identity
test_sizefloat0.2—
metricsstr—Comma-separated metric names, as an alternative to wiring a Metrics Bundle
seedint42—
deterministicbooltruePins seeds so a rerun reproduces the run
epochsint10Deep-learning strategies only
batch_sizeint32—
learning_ratefloat0.001—
optimizerselectautocustom_input adds an Optimizer input port for an external optimizer block
lossselectautocustom_input adds a Loss Fn input port
deviceselectautoauto · cpu · cuda · mps

Training more than one model? A trainer's Model port takes one wire. Wire your models into a Model Collection — it lives in the Multiple Models palette category, just below Training.

Dedicated trainers

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Each kind of training has its own block, because each has a different training loop. They share the BCILattice Trainer’s settings (split, epochs, optimizer…) and add only their own. Fine-Tuning Trainer: Base Model + Frozen Layers. DANN Trainer: Source Dataset/Labels, unlabelled Target Dataset, optional Domain Discriminator. Contrastive Trainer: masked-signal or NT-Xent pretraining over View A / View B. Multi-Task Trainer: one encoder, weighted task heads. Class-Incremental, Domain-Incremental and Continual Learning Trainers: sequential training with replay / EWC. Distillation Trainer: Student Model trained on a frozen Teacher Model’s soft targets. Every one of them except the Contrastive Trainer takes an Evaluation Protocol on its Val/Eval input, so you choose which sessions or subjects train and which test — see Evaluation Protocol for what each trainer does with it.

Validation Scheme

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

How a trainer is validated, and the one way to cross-validate. Wire its Validation output into the BCILattice Trainer’s Val/Eval input: the trainer then trains and scores once per fold and reports mean ± confidence interval with out-of-fold predictions, instead of holding out one split. By default it also refits one final model on every row, so the trainer still hands a trained model to whatever follows. With strict_leakage_check on (the default), a non-grouped scheme over data spanning more than one subject or session STOPS the run with an actionable message rather than quietly reporting an inflated score. The Val/Eval input takes only this block or an Evaluation Protocol; a scikit-learn splitter or a bare number of folds is refused. Every run records its validation design (hold-out, cross-validation or protocol), and the Results page, the Leaderboard and Paired Statistics never mix runs validated differently.

Outputs

Validation:Any

Settings

SettingTypeDefaultDescription
schemeselectstratified_k_foldleave_one_group_out is LOSO / leave-one-session-out, depending on group_by
n_splitsint5—
n_repeatsint10Repeated schemes only
group_byselectautoWhere the group of each trial comes from for a grouped scheme: subject for leave-one-subject-out, session for leave-one-session-out
shufflebooltrue—
seedint42—
test_sizefloat0.2shuffle_split only
confidencefloat0.95Confidence level for the interval on the aggregate score
strict_leakage_checkbooltrueStop on a leakage-risk configuration instead of warning. Turn off only deliberately
refit_final_modelbooltrueAfter the folds, fit one model on every row so the trainer still outputs a trained model. The metrics are the fold estimate either way

Evaluation Protocol

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Which data trains a model and which data tests it. Wire its Validation output into the BCILattice Trainer’s Val/Eval input (the same input a Validation Scheme uses). Train on Session 1 and test on Session 1 (a held-back part) and on every other session; train each session in turn and test on the others, so indoor → outdoor and outdoor → indoor both run; or train on fifteen named subjects and test on the other five. Several values named to train on are combined into one model; each in turn trains one model per value. As trained, a model is fitted on its training part and never sees a row of a part it is tested on; fine_tune adds a second, separately reported model that is given a labelled slice of it. Every dedicated trainer that scores against labels takes it too, each in its own way — the DANN Trainer adapts to each test session’s data without its labels and reports the unadapted score beside it; the Fine-Tuning Trainer fine-tunes on a labelled slice of each test session (target_size) and is scored on the rest, beside the score before fine-tuning; the Class-Incremental, Domain-Incremental and Continual Learning Trainers learn the sessions as a sequence in the order you name them and are scored on every session after every step; the Multi-Task and Distillation Trainers evaluate like the plain trainer. The Contrastive Trainer has no labels to score against and refuses it. The headline metric is the mean over the train → test pairs, which is the cross-session or cross-subject claim; within_accuracy is the same-part check beside it, and every pair gets its own row (‘Session 1 -> Session 2 accuracy’). A run whose jobs hold one session each stops and names the Select Files ‘Runs’ setting to change rather than switching it for you. It has no input: everything is set on its card. The same-session check (within_check) scores the model on trials of its own training session it never trained on — hold-out sets some aside, k-fold repeats that in rounds and averages. The card and the property panel show only the settings your choices use (train_values only when train_on is named, target_size only while fine_tune is on or a Fine-Tuning Trainer is wired, source_size only for source + target, check_before_transfer only for the Fine-Tuning or DANN Trainer) and the panel says under each one what it does. Set fine_tune (default none) to also fine-tune every pair. target only: the model is trained further on target_size (default 0.2) of the other session, with labels, and tested on the rest of it. source + target: it is trained further on source_size of its own training session together with target_size of the other session, so it does not forget its own session, and it is tested on the rest of the other session and on the trials of its own session it never trained on. Either way the score as trained stays beside it. Set direction to one pair (e.g. indoor -> outdoor) to run one way only; both ways is the default. A model that cannot train further (LDA, SVM and the other classical models) is trained again from zero instead: on its whole training session plus the slice for target only, on the two slices for source + target. Every model the protocol trains is kept under its own name for export, e.g. ‘CNN · trained on indoor’. The overlap guard is always on: overlapping samples refuse a row hold-out.

Outputs

Validation:Any

Settings

SettingTypeDefaultDescription
acrossselectsessionWhat the data is cut along. Session uses the session names in your dataset, so sessions named indoor and outdoor are trained and tested on by those names
directionselectboth waysboth ways: every session trains a model and is tested on the others. One pair runs that way only: train on the first, test on the second. The pairs are listed from the session names in your Select Files block; picking one hides train_on and test_on
train_onselecteach in turneach in turn: one model per value, tested on the others. named: ONE model trained on train_values together
train_valuesstr—Comma-separated names, e.g. "Session 1" or "sub01, sub02". A name not in the data stops the run and lists the names that are
test_onselectall othersall others · named
test_valuesstr—Used when test_on is named. A value cannot be named on both sides
within_checkselecthold-outAlso score the model on its own training session, on trials it did not train on, so the drop to other sessions is visible. hold-out sets some trials aside; k-fold repeats that in rounds and averages (steadier with few trials); none skips it. Plain trainer only for k-fold
within_foldsint5k-fold only: how many rounds, each setting a different part aside
check_before_transferbooltrueDANN / Fine-Tuning Trainer only: also test on the new session BEFORE the transfer (train indoor, test indoor, test outdoor, transfer to outdoor, test outdoor again), so the gain from the transfer is a measured number
within_sizefloat0.2Fraction of the training part held back for the same-part check
fine_tuneselectnoneAlso fine-tune each model for every other session and test it again, beside the score as trained. target only: on a labelled slice of the other session. source + target: on a slice of its own training session together with a slice of the other session, so it does not forget its own session. Plain, Multi-Task and Distillation trainers
target_sizefloat0.2The fraction of each test part used, with its labels, to fine-tune; the rest is what gets scored. Also the Fine-Tuning Trainer’s slice
source_sizefloat0.2source + target only: the fraction of its own training part the model fine-tunes on as well (1 = all of it). Taken from trials it already trained on, never from the ones held back to test it
seedint42—

Nested CV

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Cross-validation when you are also tuning hyperparameters. Choosing settings by looking at cross-validation scores and then reporting those same scores inflates the result. Nested CV runs two loops: the outer loop estimates performance, and inside each outer training fold an inner loop picks the hyperparameters — so no test fold ever influences the choice. The report also says whether the 'best' setting changed between outer folds, which tells you if it was ever a real property of the data.

Inputs

Dataset:AnyLabels:AnyModel:AnyGroups:AnySearch Space:AnyMetrics:Any

Outputs

Metrics:AnyOuter Scores:AnySelected Params:AnyNested Report:AnyPredictions:AnyTrue Labels:AnyConfusion Matrix:AnyGraph:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
outer_strategyselectleave_one_group_outEstimates performance. Use a grouped scheme when data spans several subjects
outer_splitsint5—
inner_strategyselectstratified_k_foldSelects the hyperparameters, inside each outer training fold only
inner_splitsint3—
search_spacestr—One parameter per line, e.g. "C: 0.1, 1, 10". A wired Search Space port wins over this
searchselectgridgrid · random
n_iterint10Random search only
scoringstr—What the inner loop maximises. Blank picks a sensible default for the task
group_byselectautoauto · none · subject · session · subject_and_session · task · paradigm · dataset · quality
task_typeselectautoauto · classification · regression
metricsstr——
metrics_presetselectstandardminimal · standard · full
use_default_metricsbooltrue—
seedint42—
confidencefloat0.95—
strict_leakage_checkbooltrueStop when the outer scheme could put one subject on both sides of a split

Time-Resolved Decoder

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

When in the trial can the classes be told apart? Trains one decoder per time point of epoched data (sliding), or trains at each time point and tests at every other one (generalizing — a temporal-generalization matrix). Gives a decoding curve over time instead of one number, and can run a cluster permutation test to say which stretches of the curve are really above chance. Wire an Estimator, not a trainer: it cross-validates internally.

Inputs

Data:AnyLabels:AnyEstimator:AnyGroups:AnyChannel Layout:Any

Outputs

Scores:AnyFold Scores:AnyTime Axis:AnyPatterns:AnyPatterns Topomap:AnyClusters:AnyMetrics:AnyDecoding Report:AnyGraph:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
modeselectslidingsliding · generalizing
cv_strategyselectstratified_k_foldk_fold · stratified_k_fold · group_k_fold · stratified_group_k_fold · leave_one_group_out · leave_one_out · time_series · shuffle_split · repeated_stratified_k_fold · repeated_group_k_fold
n_splitsint5—
scoringselectaccuracyaccuracy · balanced_accuracy · roc_auc · f1_macro
time_stepint1Decode every Nth sample — faster, coarser curve
sfreqfloat0Sampling rate for the time axis. 0 reads it from the data
tminfloat0Time of the first sample, in seconds
group_byselectautoauto · none · subject · session · subject_and_session · task · paradigm · dataset · quality
seedint42—
n_jobsint1—
cluster_testboolfalseRun the cluster permutation test on the curve
n_permutationsint1000—
cluster_alphafloat0.05—
channel_layoutstr——
montagestrstandard_1020Electrode positions for the patterns topomap

Pseudo Label

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Turns a model's confident predictions on unlabelled trials into training labels — the core of semi-supervised learning. Wire Evaluate Model's Probabilities and Predictions in, and the selected trials come out on Pseudo Labels, ready for a second training pass (wire that back into a trainer and you have self-training). The port is deliberately not called Labels: scoring a model against its own pseudo-labels measures only its agreement with itself, and that wiring is refused.

Inputs

Data:AnyProbabilities:AnyPredictions:AnyLabels:Any

Outputs

Data:AnyPseudo Labels:AnySelection Report:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
strategyselectthresholdHow confident trials are chosen
confidence_thresholdfloat0.95—
max_per_classint0Cap per class (0 = no cap). Stops the easy majority class taking over — the report shows class balance before and after
include_labelledbooltrueKeep the trials that already had real labels in the output
partition_namestr——

Multiple Models

Every block for working with several models or runs side by side — training them together, keeping one, or telling them apart — in one palette category: Multiple Models (BCILattice), directly below Training. Start from the question you are asking:

Your questionBlock
I want to train several models on the same dataModel Collection
I want the pipeline to keep only the best oneModel Selector
Is model A really better than model B, or is the gap noise?Statistical Comparison
I have many runs and want one table with confidence intervalsRun Aggregator
When in time do two decoding curves differ?Decoding Curve Comparison

Keeping models separate is not combining them. Blocks that merge several models into one stay where they were: Stacking Assembler (a meta-learner on top of base models) and Ensemble Voter (one prediction from many). The blocks below keep every model separate.

Model Collection

Multiple Models (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Train several models on the same data in one run. A trainer's Model port takes one wire, so wire every model into Model 1, Model 2, … and the Models output into any trainer — BCILattice Trainer (with or without a Validation Scheme), a dedicated trainer, Nested CV. Each subject's recordings are loaded ONCE and every model trains on them, and each model gets its own results row (named '<workflow> · <model>') in the Training dashboard, the Experiment Hub, Results and Model Analysis — as if you had built one workflow per model.

Inputs

Model 1:AnyModel 2:Any… up to Model 12:Any

Outputs

Models:Any

Settings

SettingTypeDefaultDescription
n_inputsint2Number of Model N ports, 1–12. Drag a wire onto a full collection and it grows by itself
model_namesstr—Comma-separated names, one per port ('CNN, LSTM, GRU'). A blank entry keeps the name of the block wired into that port — needed when several models end in a layer with the same label

You don't have to place it by hand. The canvas won't let a second wire land on an occupied input: drag a second model onto a trainer's Model port and it offers “Add a Model Collection”, which inserts one and rewires both models into it in a single undo step. A third model dropped on the trainer joins the same collection. Graphs saved before this guard existed are refused at run time with the same fix named. It also works inside a compiled Pipeline: each model still gets its own results row.

Model Selector

Multiple Models (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Keep only the best one. Takes up to 12 candidate models plus one score per model on its Metric port, and passes on the winner (highest score, or lowest for a loss) as Best Model with its Best Score. Use it when the rest of the pipeline should continue with one model; use Model Collection alone when you just want to see every model's results.

Inputs

Model 1:AnyModel 2:Any… up to Model 12:AnyMetric:Any

Outputs

Best Model:AnyBest Score:Any

Settings

SettingTypeDefaultDescription
n_inputsint3—
metric_modeselectmaxmax for accuracy-like scores, min for losses and errors
selection_criteriaselectvalidationvalidation · test · cross-val

Statistical Comparison

Multiple Models (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Is model A really better than model B, or is the gap noise? A pairwise significance test: McNemar's exact test for two models' predictions on the same trials, or a paired t-test / Wilcoxon signed-rank test for paired scores (per-fold or per-subject accuracy). 'auto' picks the right test from what is wired in.

Inputs

Predictions A:AnyPredictions B:AnyTrue Labels:Any

Outputs

p_value:Anysignificant:AnyReport:Any

Settings

SettingTypeDefaultDescription
testselectautoauto · mcnemar · paired_ttest · wilcoxon
alphafloat0.05Significance threshold

Run Aggregator

Multiple Models (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Many runs in one table. Wire a ForEach's Output into Items, or up to eight trainers' Metrics into Metrics 1–8, and it reports mean ± confidence interval per group, a learning curve when the runs sweep a number (training-set size, seeds), and — once you name a baseline — paired differences with effect sizes and multiple-comparison-corrected p-values. Without a baseline it only describes; it never picks your control for you.

Inputs

Items:AnyMetrics 1:Any… up to Metrics 8:Any

Outputs

Table:AnySummary:AnyCurve:AnyComparison:AnyMetrics:AnyReport:AnyGraph:Any

Settings

SettingTypeDefaultDescription
labelsstr—Names for Metrics 1…8, in order ("baseline, adapted") — otherwise the report reads "Metrics 1 vs Metrics 2"
baselinestr—The group every other group is compared against. Blank = describe only, no comparison
metricsstr—Which metrics to keep. Blank keeps every metric the runs reported
primary_metricstr—The metric the curve and the comparison use. Blank takes the first one present
confidencefloat0.95—
testselectautoauto · paired_t · wilcoxon
correctionselectfdr_bhMultiple-comparison correction across the contrasts
alphafloat0.05—
thresholdstr—An accuracy the study needs; blank asks for none
label_fromselectitemGroup a ForEach run by its item value (a sweep over sizes or seeds) or its position

Decoding Curve Comparison

Multiple Models (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

When in time do two decoding curves differ, and which one is higher? Two time-resolved curves can each beat chance and still be indistinguishable from each other, and comparing their peaks tests nothing. This runs a cluster-mass permutation test on the paired difference of two Time-Resolved Decoders' Fold Scores and reports the time windows where they genuinely differ.

Inputs

Fold Scores A:AnyFold Scores B:AnyTime Axis:Any

Outputs

Comparison:AnyClusters:AnyDifference:AnyMetrics:AnyGraph:Any

Settings

SettingTypeDefaultDescription
name_astrA—
name_bstrB—
cv_strategyselect—The scheme that produced the fold scores. Blank = unknown, and the result is reported as not publication-grade rather than assumed fine
n_permutationsint1000—
alphafloat0.05—
seedint42—

Transfer Protocols & Model Reuse

For the everyday protocols — train on one session and test on the others, each session in turn, named subjects to train and test — use Evaluation Protocol on the trainer. These four blocks are for everything else, and make two things drawable rather than hard-coded: a transfer-learning protocol as wiring instead of a matrix of dropdowns (“train on 70% of session A, measure the drop on session B, fine-tune on a slice of B” is four edges, not a setting nobody anticipated), and bringing a model trained in an earlier run back onto a canvas — something no amount of wiring inside one run could ever do.

Split by Domain

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Cuts data into two named partitions (A and B) along one axis: the recording's own provenance (session, subject, task, paradigm, dataset, quality) or the wired labels (class — whole categories held out, the cut a zero-shot or open-set protocol makes). The unit follows split_by: rows takes a FRACTION (0.3 = 30% to B, stratified on the labels if they're classes), everything else takes a COUNT of groups to hold out — 0.3 of a subject is not a thing, and the block refuses the wrong unit by name.

Inputs

Data:AnyLabels:AnyGroups:Any

Outputs

Data A:AnyLabels A:AnyData B:AnyLabels B:AnySplit Report:Any

Settings

SettingTypeDefaultDescription
split_byselectrowsrows · session · subject · class · task · paradigm · dataset · quality
holdout_sizefloat0.3Fraction (rows) or count of groups (everything else)
holdout_valuesstr—Name the exact sessions/subjects that go to B ("S2", or "sub18, sub19") — beats holdout_size when set, so the protocol is reproducible rather than seed-dependent
name_astrA—
name_bstrB—
seedint42—

Evaluate Model

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Scores an already-trained model on data it never saw, and never fits. The missing primitive for transfer-learning work: a trainer only ever reports on its own held-out split, so 'train on session A, measure the drop on session B' had no representation on the canvas at all before this block. Purely predict-and-score — a test asserts the wired model's parameters are unchanged after it runs.

Inputs

Model:AnyData:AnyLabels:Any

Outputs

Metrics:AnyPredictions:AnyProbabilities:AnyTrue Labels:AnyEvaluation:Any

Settings

SettingTypeDefaultDescription
evaluation_namestr—Prefixes the metric names, so several Evaluate Model calls on one model land as distinct rows ("session_b_accuracy") instead of overwriting each other
task_typeselectautoauto · classification · multi_label · regression
metricsstr—Comma-separated metric names

The transfer-learning protocol, as a graph: Select Files (Across subjects) → Split by Domain (session, holdout_values="S2") → A / B → Split by Domain (rows, 0.3) on A → train / test → Trainer(standard) → Model → Evaluate Model on test (baseline) and on B (the drop) → Trainer(fine_tuning, Base Model=Model) on a slice of B → Model' → Evaluate Model again (recovery). Every edge in that sentence is a real wire; nothing in it is a setting that had to be anticipated in advance.

Load Trained Model

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Puts a model trained in an EARLIER run back on a canvas, weights and all. Within one run, reusing a trained model is a wire — drag the trainer's Trained Model output wherever it's needed. Across runs there was nothing: an autoencoder trained, saved and exported could not be got back onto a canvas at all. This rebuilds the architecture exactly as the original run did, applies the saved weights by node id, and reports — for every node, not just the ones that matched — whether it loaded.

Outputs

Model:AnyLoad Report:AnyArchitecture:Any

Settings

SettingTypeDefaultDescription
sourceselectpackagepackage is a .bltm file (architecture + weights in one); registry is a saved name + version
file_pathfile—.bltm only — a bare .bltw carries no architecture and is never picked here
model_namestr——
model_versionstr—Blank means the latest version of model_name
collection_modelstr—Which model, when the saved graph trained several through a Model Collection. Blank reads the package's own stamp — a package exported from one model's results row already knows which model it is — and the block refuses by name, listing every model in the file, when it still can't tell
use_training_knowledgebooltrueOn: load the trained weights (the reason to reach for this block). Off: the published ARCHITECTURE with fresh initialisation — train it yourself on your own data
freezebooltrueSkipped when use_training_knowledge is off — a frozen, randomly-initialised network cannot learn and reports no error while failing to
strictbooltrueRefuse a partial load outright rather than proceed with some nodes at their initialisation. The Load Report names every node either way

No inputs, on purpose. Where the model comes from is a setting, and the file carries its own architecture, so there is nothing left for a port to supply. A model that is 60% pretrained and 40% random scores like neither the pretrained model nor a fresh one — strict refuses that outright rather than proceeding quietly.

Forward Pass

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

output = model(data) — the step every use of a loaded model needs, and the one no other block performs. Evaluate Model looks close but scores against ground truth, so it cannot be used where there are none: an autoencoder's latent codes, an encoder's embeddings, a frozen trunk's features for a new head, a saved classifier's raw outputs on a fresh recording. Framework-neutral: torch models are called, an sklearn-API estimator is asked for predict / transform / predict_proba — model(X) on a RandomForest raises, so auto resolves the right convention rather than assuming one.

Inputs

Model:AnyData:AnyData 2:AnyData 3:Any

Outputs

Output:AnyCall Report:Any

Settings

SettingTypeDefaultDescription
callselectautoauto · __call__ · predict · predict_proba · transform · encode
n_inputsint1Data ports actually wired, up to 3 — a two-stream network or a model with a mask
no_gradbooltrueOff keeps the autograd graph — what you want when this feeds a trainer, so gradients pass THROUGH a frozen trunk to the head behind it. On is inference
eval_modebooltrueDropout/BatchNorm behave differently in eval; the module is restored to its previous mode afterwards either way
output_asselectautoauto · array · tensor

Evaluation

Blocks that ask a harder question of a trained model than “what is its accuracy?” — would it work live, what did it use, and how should a ranking, a rejection or a reconstruction be scored.

Pseudo-Online Evaluator

Evaluation (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Would this decoder work in a live session? Offline scores are optimistic: they are computed on epochs, so the decoder is told where each trial starts. This block slides a window over the continuous recording with no trial boundaries, matches confident outputs against the event markers, and reports false activations per minute, detection latency and information transfer rate (ITR). A 92% offline decoder that fires eleven times a minute at rest is not a 92% decoder.

Inputs

Model:AnyData:AnyEvent Markers:Any

Outputs

Metrics:AnyTimeline:AnyPredictions:AnyOnline Report:AnyGraph:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
window_msfloat1000Length of each decoding window
stride_msfloat100Step between windows
decision_thresholdfloat0.7Confidence needed before an output counts as a decision
refractory_msfloat1000Minimum gap between two decisions
tolerance_msfloat1000How late a decision may be and still match its event
rest_classstr—The label meaning "no command" — its outputs are never activations
causal_onlybooltrueUse only past samples in each window, as a live system must
sfreqfloat00 reads the sampling rate from the data

Neuro Explainer

Evaluation (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Which channels, frequency bands or time windows did the model rely on — drawn on a head. It groups feature importance by the feature names (so 'C3|beta' counts toward channel C3 and the beta band) and renders a topomap, a time course and a spectrum. For linear models it reports patterns, not raw weights: a large weight can belong to a channel that only cancels noise, and every output is labelled 'patterns' or 'filters' so a figure never says the wrong one.

Inputs

Model:AnyData:AnyLabels:AnyFeature Names:AnyChannel Layout:Any

Outputs

Importance:AnyMetrics:AnyTopomap:AnyTime Course:AnySpectrum:AnyReport:AnyGraph:Any

Settings

SettingTypeDefaultDescription
methodselectpermutationpermutation works for any model; patterns/filters need a linear one
axisselectchannelWhat importance is grouped by
per_classboolfalse—
n_repeatsint10Permutation repeats
scoringstr——
seedint42—
montagestrstandard_1020Electrode positions for the head plot
channel_layoutstr——

Embed & Retrieve

Evaluation (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

For when the answer is a ranking, not a class: which of these 200 stimuli was the person looking at? Embeds each trial, ranks a candidate set (usually a Candidate Bank) by similarity, and reports top-1 / top-k accuracy, recall@k, median rank and mAP — each against the chance level of that particular bank, since top-5 out of 10 and top-5 out of 1,000 are very different claims.

Inputs

Model:AnyData:AnyEmbeddings:AnyCandidate Bank:AnyGround Truth Index:AnyLabels:AnyBank Labels:Any

Outputs

Ranks:AnyTop-K:AnyMetrics:AnyReport:AnyProvenance:Any

Settings

SettingTypeDefaultDescription
metricselectcosinecosine · euclidean
top_kint5—
bank_sourceselectportWhere the candidates come from — port reads the Candidate Bank input

Open-Set Scorer

Evaluation (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Gives a classifier the option to answer 'none of these'. A normal classifier handed a class it never saw still picks one of the classes it knows, confidently and wrongly. This scores how familiar each trial looks (max softmax, energy, distance…), rejects the unfamiliar ones at a declared threshold, and reports how well known and unknown trials are separated (AUROC).

Inputs

Model:AnyData:AnyLabels:AnyPredictions:AnyKnown Classes:AnyTrain Data:AnyTrain Labels:Any

Outputs

Metrics:AnyFamiliarity:AnyAccepted:AnyReport:AnyProvenance:Any

Settings

SettingTypeDefaultDescription
scoreselectmax_softmaxmax_softmax · max_logit · energy · distance · novelty
thresholdstr—Familiarity below this is rejected
target_false_alarmstr—Or set the threshold from an acceptable false-alarm rate
known_classesstr——
metricsstr——

Reconstruction Evaluator

Evaluation (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Scores a reconstructed stimulus — an image decoded from brain activity — against the real one: SSIM, PSNR and correlation, shown side by side. It also runs an identity check (is each reconstruction closer to its own stimulus than to the others?), because a blurry average image can score well on pixel metrics while recovering nothing specific to any trial.

Inputs

Predictions:AnyTargets:Any

Outputs

Metrics:AnyComparison Grid:AnyReport:AnyProvenance:Any

Settings

SettingTypeDefaultDescription
metricsstr——
mean_baselinebooltrueAlso score the mean image, the baseline a real reconstruction must beat
target_shapestr—Picture shape of the flat target rows, e.g. "8,8"
grid_columnsint6—

Model Structure

Blocks that shape a model before it is trained. Model Concat and Model Add are in Custom Blocks.

Model Pipeline

Model Structure (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Chains preprocessing steps and an estimator into ONE model (e.g. CSP → LDA), so cross-validation refits every step inside each fold. That matters for anything that learns from labels — a CSP filter fitted once on the whole recording has already seen the test trials, and the score is inflated. Wire the steps into Step 1, Step 2, … in order, with the estimator last.

Inputs

Step 1:AnyStep 2:Any… up to Step 5:Any

Outputs

model_obj:AnyReport:Any

Settings

SettingTypeDefaultDescription
step_namesstr—Optional names for the steps, comma-separated

Expression Layer

Model Structure (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

A small calculation inside a network, with no weights — for example torch.log1p(x), or reshaping between two layers. Chain it between layer blocks like any other layer. The expression is limited to array operations; it cannot run arbitrary code.

Inputs

model_obj:Any

Outputs

model_obj:Any

Settings

SettingTypeDefaultDescription
expressionstrxIn terms of x, the input tensor
layer_roleselecthiddenfirst · hidden · last
input_shapestrauto—

Neural Prefix Encoder

Model Structure (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Brain-to-text. Learns to map neural features onto a few 'prefix' embeddings that a frozen language model reads before generating text. Only this mapping is trained; the language model is untouched. Every decode is reported beside two controls — the same model fed shuffled and zeroed brain features — because a language model generates fluent text from anything, and only the gap to the controls shows the brain signal mattered.

Inputs

Features:AnyCaptions:AnyDecoder:AnyTokenizer:AnyCandidate Bank:Any

Outputs

Generated Text:AnyMetrics:AnyReport:AnyProvenance:Any

Settings

SettingTypeDefaultDescription
decoder_sourceselectwiredwired · fetched
decoder_modelstr——
prefix_lengthint4How many prefix embeddings the brain features become
d_modelint00 reads the language model's embedding size
epochsint150—
learning_ratefloat0.05—
holdoutfloat0.3—
controlsselectshuffled,zeroedshuffled,zeroed · shuffled · zeroed
primary_metricselectrouge_lrouge_l · bleu · bertscore
metricsstrbleu,rouge_l—
max_new_tokensint0—
seedint42—

Neural Image Prefix

Model Structure (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Brain-to-image. Learns to map neural features into the conditioning space of a frozen image decoder, which then draws the picture. Only the mapping is trained. Scored on pixel correlation, SSIM and CLIP score plus the identity check, always beside the shuffled- and zeroed-feature controls.

Inputs

Features:AnyStimulus Images:AnyLatent Decoder:Any

Outputs

Generated Images:AnyMetrics:AnyReport:AnyProvenance:Any

Settings

SettingTypeDefaultDescription
target_shapestr——
epochsint150—
learning_ratefloat0.05—
holdoutfloat0.3—
controlsselectshuffled,zeroedshuffled,zeroed · shuffled · zeroed
primary_metricselectpixel_correlationpixel_correlation · ssim · clip_score
metricsstrpixel_correlation,ssim,clip_score,fid—
seedint42—
decoder_sourceselectwiredwired · fetched
decoder_modelstr——

Data Adapters

Blocks that get data into the shape the next block needs, or bring in a set that is not one row per trial.

Epoching

Preprocessing (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Cuts continuous rows (one per recorded time point) into samples for a model, sized in the unit you think in: seconds, Hz or rows — one at a time. The same settings as Select Files' Samples, for data that reached a wire some other way (a filter step, a compiled pipeline's input). It refuses data that is already cut into samples, so nothing is epoched twice, and a sample never spans two recordings. Stacked samples come out as samples × channels × steps; feed Epoch Features for a classical model.

Inputs

Data:AnyLabels:Any

Outputs

X:AnyY:Any

Settings

SettingTypeDefaultDescription
sample_byselectsecondsHow many recorded rows make one sample for the model, in the unit you think in. On a 10 Hz device, 0.2 seconds, 5 Hz and 2 rows are the same answer. Only one unit at a time
sample_sizefloat1The number, in the unit sample_by names (seconds, Hz or rows)
combineselectautostack keeps the rows as time steps (samples × channels × steps); average makes one row per sample (a lower rate). auto: average for Hz, stack otherwise
overlap_percentfloat0How much each stacked sample shares with the next. Overlapping samples must be validated with whole recordings held out
window_labelselectskip mixedThe label of a sample whose rows carry different labels. skip mixed drops it rather than inventing one
device_rate_hzfloat0The recording's rate in Hz. 0 uses the rate of the recordings Select Files loaded; rows need no rate

Epoch Features

Preprocessing (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Turns epoched data (trials × channels × time) into one row of features per trial, which is what classical classifiers need. Pick how: summary statistics per channel (mean, spread, range, RMS, roughness), the average over time, a few time windows, or everything flattened. Features are named by channel, so Neuro Explainer can later draw importance on a head. Trials are never mixed up or reordered.

Inputs

Epochs:AnyLabels:Any

Outputs

Features:AnyLabels:AnyFeature Names:AnyX:AnyY:AnyData:AnyInfo:Any

Settings

SettingTypeDefaultDescription
aggregationselectchannel_statschannel_stats · flatten · mean_over_time · time_windows
n_time_windowsint4time_windows only

Projection Adapter

Preprocessing (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Takes the images Signal Projection makes (trials × channels × size × size) and either keeps them as an image stack for a CNN, picks one channel's image, summarises each image into a few numbers, or flattens them into feature rows for a classical classifier.

Inputs

Images:AnyLabels:Any

Outputs

Images:AnyLabels:AnyFeature Names:AnyX:AnyY:AnyData:AnyInfo:Any

Settings

SettingTypeDefaultDescription
modeselectimage_stackimage_stack · single_channel_image · image_stats · flatten
channel_indexint0single_channel_image only

Candidate Bank

Inputs (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Brings in a set of candidates — stimuli, sentences, images — that is NOT one row per trial: 200 candidate stimuli for 40 trials, say. That is what retrieval (Embed & Retrieve) and generation (Neural Prefix Encoder) score against. Every other input insists on one row per trial; this one is deliberately different, and marks its output so nothing downstream mistakes it for labels.

Inputs

Items:Any

Outputs

Bank:AnyNames:AnyReport:Any

Settings

SettingTypeDefaultDescription
bank_filefile—A CSV of candidates
bank_kindselectautoauto reads a numeric table as a matrix and anything else as text
text_columnstr——
name_columnstr——
inline_itemstext—Or type the candidates here, one per line

Advanced Training

Eight blocks for the situations an ordinary BCI session actually produces: not enough labelled trials, data that cannot leave its site, classes with no examples, and labels that disagree with each other. Every one of them reports its result against a floor — a chance level, a random baseline, a held-out split — because on a two-hundred-trial cohort a number without its floor is not a result.

Federated Averaging

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Trains one shared model across several sites without pooling their rows: every site fits locally from the current global model, and the parameters are averaged (weighted by row count for FedAvg, unweighted for uniform, coordinate-wise median for Byzantine robustness). It only accepts models whose parameters are a vector space — a torch module's state_dict, or a linear estimator's coef_/intercept_ — and refuses a random forest by name, because the coordinate-wise mean of two forests' trees is not a model of anything. Always reports the centralised score on the pooled rows beside the federated one: the gap between them is the number a reader wants, and a federated score alone is unreadable. dp_noise_sigma adds Gaussian noise to the aggregate and is recorded as NOT a calibrated (ε, δ) guarantee.

Inputs

Model:AnyData:AnyLabels:AnySites:Any

Outputs

Federated Model:AnySite Report:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
roundsint3Each round restarts every site from the averaged model — one round is 'fit everywhere and average once', which is a different method
local_epochsint1Gradient steps per site per round (torch models; an sklearn site refits)
aggregationselectfedavgfedavg weights by site row count · uniform weights equally · median is coordinate-wise and ignores the weights, which is what makes it robust
learning_ratefloat0.01—
dp_noise_sigmafloat0Gaussian noise on the aggregate, relative to its own scale. NOT differential privacy — no ε is calibrated
min_site_rowsint5Sites below this are dropped and listed in the report
report_centralisedbooltrueAlso fit on the pooled rows, for the gap
seedint0—

Episode Sampler

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Turns a labelled cohort into episodes: an n-way k-shot support set and a query set drawn from the same classes, disjoint by row. This is the unit every few-shot method is defined over, and Data Splitter cannot produce it — that block cuts by ratio and knows nothing about classes. The four data ports carry the FIRST episode, which is what a classifier downstream wants; the Episodes port carries every episode's row indices, which is what Meta-Learner wants. Support/query disjointness is asserted, not assumed.

Inputs

Data:AnyLabels:Any

Outputs

Support Data:AnySupport Labels:AnyQuery Data:AnyQuery Labels:AnyEpisodes:AnyEpisode Report:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
n_wayint00 means every class — the right default for BCI, where sampling 2 of 4 motor-imagery classes would report an easier problem than the user has
k_shotint5Support trials per class
n_queryint15Query trials per class (capped by what remains after the support draw)
n_episodesint1More than one is required by Meta-Learner
seedint0—

Prototypical Adapter

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Class prototypes in an embedding space and nearest-prototype classification of the query set (Snell et al., 2017). Non-parametric — no gradients, no training loop, no torch — which is what makes it the right first few-shot block. The Encoder port is optional: without one the features themselves are the embedding. Reports accuracy against BOTH floors (uniform 1/n and the query set's majority-class rate) plus a permutation null over shuffled support labels, because with k=5 a class prototype is one noisy point and beating 1/n on a single episode happens by luck often enough to matter.

Inputs

Support Data:AnySupport Labels:AnyQuery Data:AnyQuery Labels:AnyEncoder:Any

Outputs

Predictions:AnyProbabilities:AnyPrototypes:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
distanceselecteuclideaneuclidean is the published choice · cosine ignores magnitude · mahalanobis uses one shared support covariance, because a per-class one from k=5 trials is singular by construction
temperaturefloat1Softmax temperature over the negative distances. Changes the emitted probabilities and NOT the argmax
n_permutationsint200Draws for the null band over shuffled support labels
seedint0—

Meta-Learner

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Reptile (Nichol et al., 2018) or first-order MAML over the sampler's episodes: adapt on the support set, measure on the query set, and move the initial parameters toward what adaptation found. Both are the same loop with a different meta-update, and which ran is recorded in the provenance. Refuses a single episode — adapting to one task and reporting the result is fine-tuning, and labelling it meta-learning makes the number indistinguishable from a real meta-learned initialisation. Reports the adaptation gain, not only the final accuracy: an initialisation that adapts no better than the one it started from has not learned to learn. Needs PyTorch. Requires PyTorch — the block refuses with the install command when it is absent.

Inputs

Model:AnyEpisodes:Any

Outputs

Meta Model:AnyAdaptation Trace:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
algorithmselectreptilereptile moves the initial parameters toward the adapted ones · fomaml moves them along the query-set gradient measured after adaptation
inner_stepsint5Gradient steps on each episode's support set
inner_lrfloat0.01Step size for the inner (task) loop
meta_lrfloat0.1Step size for the outer (initialisation) update
meta_epochsint1Passes over the whole episode set
seedint0—

Zero-Shot Classifier

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Predicts classes that have no training trial of their own, by describing them with a semantic vector instead of with examples. Learns a ridge compatibility map from neural features into the semantic space on the SEEN classes, then ranks every candidate — seen and unseen — for a query trial (the ESZSL / DeViSE family). Different from Embed & Retrieve, which ranks candidate items rather than classes. The unseen classes are declared explicitly and the block refuses when one of them appears in the training labels: that is ordinary classification under a zero-shot label, and it is the easiest such claim to make by accident. Seen and unseen accuracy are reported separately — a pooled 'generalised zero-shot' number is dominated by the seen classes.

Inputs

Data:AnyLabels:AnyQuery Data:AnyQuery Labels:AnyClass Semantics:Any

Outputs

Predictions:AnyScores:AnyRanking:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
unseen_classesstr—Comma-separated class names withheld from training. Required — a block that inferred them would confirm whatever the graph happened to do
similarityselectcosineHow a projected trial is scored against each class vector
alphafloat1Ridge penalty. Unregularised, the map memorises the seen classes, which is exactly the direction that flatters zero-shot
top_kint3Size of the reported ranking
n_permutationsint200Draws for the null band over shuffled class-to-semantic assignment
seedint0—

Active Learning Sampler

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Selects which unlabelled trials are worth a person's time. Pseudo Label's mirror — both consume the Probabilities port Evaluate Model already emits, and together they are the whole label-efficiency loop: confident rows become labels for free, uncertain rows become a labelling queue. Six strategies that genuinely disagree, including random, which is a real strategy because an honest comparison needs it. Every run computes the same selection statistics for a random batch of the same size; with Pool Labels wired (a simulation) it also reports the model's error rate on the selected rows against a random batch, which is the direct statement of whether the strategy found the hard trials.

Inputs

Pool Data:AnyProbabilities:AnyCommittee:AnyLabelled Data:AnyPool Labels:Any

Outputs

Selected Data:AnySelected Indices:AnySelected Labels:AnyRemaining Data:AnyQuery Scores:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
strategyselectmarginmargin (top-1 minus top-2) is strongest on multi-class · entropy suits a well-calibrated many-class model · qbc_vote_entropy needs a Committee · core_set is greedy k-centre and ignores the model, so it is the cold-start choice · random is the baseline
batch_sizeint10Rows to query. Selecting the whole pool is refused
diversity_weightfloat00 is pure uncertainty ranking. Above 0, blends in distance from what is already chosen — the k most uncertain trials of a session are frequently the same artefact seen k times
seedint0—

Label Model

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Combines several unreliable labellers into one probabilistic label. The situation is ordinary in a BCI lab and had no expression on the canvas: ground truth is not a column but several columns that disagree — a stimulus marker, a button press, a rater's annotation, a threshold rule over EMG, an earlier model. Custom Labels takes one column; Pseudo Label takes a model's own belief; neither combines sources. Dawid-Skene estimates a per-source confusion matrix and a class prior jointly with the labels, from the sources' agreement pattern alone. Abstention is first class — a labeller that fires on 12% of trials and is always right is more valuable than one that always fires and is right 70% of the time — and the best single source is reported as the floor.

Inputs

Label Sources:AnyTrue Labels:Any

Outputs

Labels:AnyProbabilities:AnyConfidence:AnySource Quality:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
methodselectdawid_skenedawid_skene is the 1979 EM estimator · majority_vote counts sources equally, which is wrong when one dominates · weighted_vote is the one-pass approximation
abstain_valuestr-1The sentinel for 'this source declined'. -1 is scikit-learn's unlabelled convention across its whole semi-supervised module
max_iterint100EM iteration cap
tolfloat0.0001EM convergence threshold on the posterior
min_coveragefloat0Drop sources that fire on less than this fraction of rows
seedint0—
Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Searches depth, width, dropout, activation and learning rate, and reports the result honestly — which is the whole problem. A search that evaluates 40 architectures on one validation split and reports the best is reporting the maximum of 40 noisy estimates, biased upward by roughly their spread; it has found the architecture that got lucky, not a better one. So selection happens on an inner split and the reported number comes from rows neither the search nor the training touched (the Held-Out ports, or an outer split cut before the search begins), with the difference named selection_bias. It also reports the spread over its own candidates: a winner inside that spread means the search found sampling noise. Needs PyTorch. Requires PyTorch — the block refuses with the install command when it is absent.

Inputs

Data:AnyLabels:AnyHeld-Out Data:AnyHeld-Out Labels:Any

Outputs

Best Model:AnyBest Architecture:AnySearch Trace:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
strategyselectrandomrandom is the strong baseline the literature keeps rediscovering · evolution mutates the best · successive_halving trains everything briefly, keeps the top half, trains longer
n_candidatesint16Architectures evaluated
epochsint40Full-budget training steps per candidate
depthsstr1,2,3Comma-separated option list. A discrete list is what the search enumerates, and it lets an axis be pinned by giving it one value
widthsstr16,32,64,128Comma-separated hidden widths
dropoutsstr0.0,0.25,0.5Comma-separated dropout rates
learning_ratesstr0.001,0.003,0.01Comma-separated learning rates
activationsstrrelu,gelu,tanhComma-separated from relu · gelu · tanh · elu
holdout_fractionfloat0.25Used only when the Held-Out ports are empty
seedint0—

Uncertainty & Causality

How sure the model is, whether that number can be believed, and what leads what. The first two turn a softmax into something a clinical decision can rest on; the third answers a question the symmetric connectivity metrics cannot ask, and is careful about what it does not claim.

Uncertainty Estimator

Evaluation (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Per-row uncertainty, plus the calibration report that gives it meaning. A softmax output is a number between 0 and 1 that a reader treats as a probability, and on a small BCI cohort it is routinely 0.99 while being wrong a third of the time — so every run reports ECE, MCE, a reliability curve and the Brier score, and offers temperature scaling to fix what it finds. Three sources: a single model's Probabilities, an Ensemble of probability matrices, or Model + Data for MC-dropout (which refuses a network with no dropout layer, since that would report an epistemic variance of exactly zero). A sampled source separates aleatoric from epistemic uncertainty. Also reports the AUC with which the uncertainty ranks errors above correct rows — a calibration number can look fine while the uncertainty carries no information about which predictions are wrong.

Inputs

Probabilities:AnyLabels:AnyEnsemble:AnyModel:AnyData:Any

Outputs

Uncertainty:AnyCalibrated Probabilities:AnyAleatoric:AnyEpistemic:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
methodselectentropyentropy is total predictive uncertainty · max_probability and margin are the cheap proxies · mutual_information isolates the epistemic part and needs several forward passes
mc_samplesint20Forward passes with dropout left on
calibrateboolfalseFit a temperature and emit calibrated probabilities
allow_in_sampleboolfalseRequired to fit and report a temperature on the same rows. Off by default, and stamped into the provenance when on
n_binsint10Reliability-curve bins on the confidence axis
seedint0—

Conformal Predictor

Evaluation (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Split conformal prediction: a SET of classes with a finite-sample, distribution-free coverage guarantee. The only construct in the suite that can say 'the true class is in here 90% of the time' and mean it, which is what a clinical BCI decision needs and what a calibrated softmax still does not provide. Separate Calibration and Test ports and no single-port mode at all, because a guarantee fitted on the rows it is measured on is not a guarantee and on a canvas that mistake is one wire. Refuses a calibration set too small for the requested α — with n calibration points the smallest achievable miscoverage is 1/(n+1). Reports the empirical coverage beside the requested one; empty sets are repaired to their top-1 class and the repair is counted, never silent.

Inputs

Calibration Probabilities:AnyCalibration Labels:AnyTest Probabilities:AnyTest Labels:Any

Outputs

Prediction Sets:AnySet Labels:AnySet Sizes:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
methodselectlaclac gives the smallest average set · aps adapts the set size per trial and is better conditioned on hard examples
alphafloat0.1Miscoverage rate: 0.1 requests 90% coverage
randomisedbooltrueAPS only. Without it the sets are conservative by up to one class
seedint0—

Causal Connectivity

Evaluation (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Directed influence between channels — the question Channel Graph Builder's symmetric metrics cannot ask. Granger causality (an F-test between a restricted and an unrestricted autoregression), transfer entropy (model-free, so it catches nonlinear coupling Granger misses), or partial correlation as the symmetric control. The caveat is part of the output rather than a footnote: these are statements about PREDICTION, not intervention. A common driver, volume conduction, or one channel having a better signal-to-noise ratio all produce significant directed edges between channels with no causal relationship, and on scalp EEG all three are normal — so every run stamps interventional: false and the block will not print the word 'causes'. Every edge clears a time-shifted surrogate null with a Benjamini–Hochberg correction; an uncorrected matrix on 32 channels runs 992 tests and finds ~50 edges in noise.

Inputs

Data:AnyChannel Names:Any

Outputs

Connectivity Matrix:AnyP Values:AnySignificant Edges:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
methodselectgrangergranger is linear and directed · transfer_entropy is model-free and needs far more samples · partial_correlation is symmetric and removes third-channel edges
max_lagint5Autoregression order / history length. The block refuses epochs too short to support it
n_binsint4Transfer entropy only. Raising it explodes the history state space and the estimator returns the noise of an empty histogram
n_surrogatesint50Circularly time-shifted source draws. Too few is refused, because the smallest achievable p-value is 1/(n+1) and an empty matrix reads as 'no directed structure'
alphafloat0.05Benjamini–Hochberg level over the n(n−1) tests
seedint0—

Fusion, Flows & Rules

Three blocks that change the shape of the model rather than the data reaching it: combining modalities, replacing discrete depth with a continuous flow, and putting task knowledge back on top of the decoder.

Modality Fusion

Preprocessing (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Combines EEG with fNIRS (or any two to four modalities) honestly. Feature Concatenator puts two arrays side by side, which is a fusion strategy and not multi-modal learning — it answers none of the questions that make this hard: the modalities live on wildly different scales, they carry different amounts of information, and a concatenation dominated by the wider or louder one reports a 'multi-modal' result the other did not contribute to. So every run with Labels reports a cross-validated probe accuracy for EACH modality alone and for the fusion, plus the lift over the best single modality. On EEG + fNIRS the honest answer is frequently that one modality was carrying it. Row alignment is checked, never assumed: a mismatch means the modalities came from different epoching runs.

Inputs

Modality A:AnyModality B:AnyModality C:AnyModality D:AnyLabels:Any

Outputs

Fused Data:AnyAblation Report:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
strategyselectconcatconcat standardises per modality then concatenates · reliability_weighted scales each by how far its own probe rises above chance · pca_shared builds a joint subspace when the concatenated space is wider than the trial count · cca finds the directions in which exactly two modalities covary
n_componentsint00 lets the strategy pick
standardisebooltrueZ-score each modality before fusing. Off only when the modalities are already on one scale
foldsint5Cross-validation folds for the per-modality ablation probe
seedint0—

Neural ODE Block

Model Structure (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Continuous depth: a learned vector field dh/dt = f(h, t) integrated over an interval, instead of a stack of residual layers. For neural time series the appeal is concrete — the hidden state evolves in continuous time, so irregular sampling and variable epoch lengths stop being a preprocessing problem. Fixed-step Euler, midpoint and RK4 in plain torch rather than against torchdiffeq, which keeps the determinism claim checkable and avoids a dependency for thirty lines of Runge–Kutta. Every run reports a solver-consistency number — the same field integrated again at double the step count — because an ODE with too few steps IS a residual network and the 'continuous' claim is decoration. It also reports how far the state travels: h(T) ≈ h(0) is an array of the right shape carrying the input unchanged. Needs PyTorch. Requires PyTorch — the block refuses with the install command when it is absent.

Inputs

Data:Any

Outputs

Model:AnyTrajectory:AnyODE Report:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
solverselectrk4rk4 is fourth-order and the default · midpoint second · euler first, and the one that shows a large consistency gap
n_stepsint10Integration steps over [0, t_end]
t_endfloat1End of the integration interval
hidden_dimint64Width of the vector field's MLP
n_layersint2Depth of the vector field's MLP
activationselecttanhVector-field nonlinearity. tanh keeps the field bounded, which is what most ODE work uses
time_dependentbooltrueAppend t as an input channel, making the field non-autonomous
augment_dimint0Augmented Neural ODEs. At 0 the flow cannot cross itself, so a class surrounded by another is unreachable at any width
in_featuresint00 takes it from the Data port
out_featuresint00 emits the flow's end state instead of a classification head
seedint0—

Rule Constraint Layer

Training (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Task knowledge as a symbolic layer over the decoder's probabilities. A BCI decoder does not emit predictions into a vacuum: a wheelchair cannot turn left immediately after turning right, a state must be held for a minimum dwell before it counts as intentional. This block decodes the most likely sequence the rules PERMIT — a constrained Viterbi over the whole sequence, not a filter over argmax, which is why it can repair a violation by changing an earlier prediction. Five rule forms, one per line: forbid A · forbid A after B · require A after B · min_dwell A n · max_run A n. Anything else is refused rather than ignored. Rows are read as consecutive time steps. Constraints can only lower the model's own likelihood; whether they raise accuracy is empirical, so with Labels wired the block reports accuracy before and after and splits the changes into corrections and new errors.

Inputs

Probabilities:AnyClasses:AnyLabels:Any

Outputs

Predictions:AnyConstrained Probabilities:AnyViolations:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
rulestext—A multi-line field. One rule per line; # starts a comment. An unparseable line is refused, because a rule you believe is running while it is not is worse than no rule
renormalisebooltrueRedistribute probability mass off classes the automaton could not have chosen, so a downstream calibration or conformal block sees the reachable distribution
fail_on_no_rulesbooltrueRefuse an empty rule set instead of recording that a symbolic layer ran and did nothing

Graph Learning

The montage as a graph. Channels have a known neighbourhood structure — spatial and functional — and a dense layer has to rediscover it from the few hundred trials a BCI session provides.

Channel Graph Builder

Graph Learning (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

An EEG cap is a graph, and every block in the suite treated it as a flat feature vector. This builds the channel × channel adjacency — from the data (correlation, magnitude-squared coherence, phase-locking value) or from the montage (Gaussian kernel over electrode distance) — sparsified by k-nearest-neighbour or a threshold. Useful on its own: the adjacency it emits is a connectivity matrix. Which metric is chosen decides what can be seen at all: zero-lag correlation is blind to a purely lagged coupling that coherence and PLV both find. The data-driven metrics are compared against a phase-randomised surrogate null, because a connectivity matrix on band-limited neural data has strong structure by construction and 'these channels are connected' is not a finding until it beats that.

Inputs

Data:AnyPositions:Any

Outputs

Adjacency:AnyDense Connectivity:AnyDegrees:AnyGraph Report:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
metricselectcorrelationcorrelation is zero-lag and blind to lagged coupling · coherence and plv are not · distance uses the Positions port · precomputed takes a square matrix on Data
sparsifyselectknnknn keeps each node's k strongest edges (symmetrised) · threshold cuts by weight · none keeps the dense matrix
k_neighboursint4Neighbours per node for knn
thresholdfloat0.3Minimum edge weight for threshold
distance_sigmafloat00 uses the median pairwise distance, which adapts to whatever units the montage is in
n_surrogatesint20Phase-randomised draws for the null. 0 skips it
seedint0—

Graph Neural Encoder

Graph Learning (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Symmetric-normalised graph convolution, Â = D^-½(A+I)D^-½ (Kipf & Welling), over a Channel Graph Builder adjacency. Two modes and the choice is deliberate: 'embeddings' propagates node features in pure numpy and needs no torch at all — propagation over the montage is a spatial filter and a perfectly good preprocessing step — while 'model' emits a trainable nn.Module whose adjacency is registered as a BUFFER, so a saved model still knows its montage. Reports the Dirichlet energy before and after: repeated convolution drives it to zero, at which point every node holds the same vector and the output is a constant of the right shape. The output rank is reported for the same reason.

Inputs

Adjacency:AnyData:Any

Outputs

Embeddings:AnyModel:AnyEncoder Report:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
outputselectembeddingsembeddings is numpy and needs the Data port · model is torch-gated and emits an untrained module for a trainer
n_layersint2Propagation steps. More smooths harder — watch the Dirichlet energy
hidden_dimint32Width per layer (model mode)
poolingselectmeanHow node features become a trial vector: mean · max · concat · none keeps the node axis
activationbooltrueReLU between propagation steps
seedint0—

Generative Models

Synthesising trials, for augmentation and class rebalancing. Neither block returns samples without the same three-part audit, because a generative model is the easiest thing in the suite to fool yourself with.

GAN Trainer

Generative Models (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

A conditional MLP generator and discriminator over trial features — synthesising trials for augmentation, class rebalancing and sample-efficiency questions. The other direction from Neural Prefix Encoder, which goes from neural activity to text. Samples never come back without the audit: nearest-neighbour distance to the real trials against the distance real trials sit from each other (a memorised generator produces beautiful samples and zero new information), a held-out classifier two-sample test where 0.5 means indistinguishable, and — with Labels — train-on-synthetic/test-on-real accuracy against train-on-real, which is the only number that says the samples are USEFUL rather than realistic-looking. Refuses fewer than 20 trials, where a GAN simply memorises. Needs PyTorch. Requires PyTorch — the block refuses with the install command when it is absent.

Inputs

Data:AnyLabels:Any

Outputs

Synthetic Data:AnySynthetic Labels:AnyGenerator:AnyAudit Report:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
lossselectnonsaturatingnonsaturating is the standard GAN objective · wgan_gp is the most stable on small tabular cohorts · lsgan is the least-squares variant
latent_dimint32Noise dimension
hidden_dimint128Generator and discriminator width
epochsint300Alternating generator/discriminator steps
batch_sizeint64Rows per step
learning_ratefloat0.0002Adam step size for both networks (β₁ = 0.5)
gp_weightfloat10Gradient-penalty weight for wgan_gp
n_samplesint00 draws as many samples as there are real trials
seedint0—

Diffusion Generator

Generative Models (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

DDPM over trial features: a noise schedule forward and a learned denoiser back. Slower to sample than a GAN and far more stable to train, which on a 200-trial cohort is usually the trade that matters. Conditional on the class when Labels are wired. Ships the same three-part audit as GAN Trainer — memorisation distance, classifier two-sample test, and train-on-synthetic/test-on-real utility — from the same shared implementation, because two copies of an audit drift and the drift always goes in the flattering direction. Requires PyTorch — the block refuses with the install command when it is absent.

Inputs

Data:AnyLabels:Any

Outputs

Synthetic Data:AnySynthetic Labels:AnyDenoiser:AnyAudit Report:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
scheduleselectcosinecosine (Nichol & Dhariwal) — linear betas destroy a low-dimensional feature vector's signal in the first few steps and the model then learns to denoise pure noise
timestepsint200Diffusion steps. Sampling costs one denoiser pass each
hidden_dimint128Denoiser width
epochsint400Training steps
batch_sizeint64Rows per step
learning_ratefloat0.001Adam step size
n_samplesint00 draws as many samples as there are real trials
seedint0—

Reinforcement Learning

The closed half of the loop: the decoder chooses, the user reacts, and the reaction is the training signal. The environment is a contextual bandit over the trial stream — the one a BCI lab has, rather than a simulator this application cannot honestly provide.

RL Agent Trainer

Reinforcement Learning (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

A BCI is a closed loop and the suite could only describe the open half. This learns online over the trial stream as a contextual bandit — deliberately the environment a BCI lab has, not a simulator: each row is a state, the agent picks an action, and the reward comes from the Rewards port (a real logged interaction) or is derived from the labels for a simulation. Three floors make the reward readable: the random policy's reward, the oracle's, and the agent's position between them. States are z-scored inside the block and the Q update is normalised-LMS, so learning_rate means a fraction of the step to the exact fit rather than something that depends on whether the features are microvolts or band-power ratios. Warns when the policy collapses to one action, which still beats random on an unbalanced stream.

Inputs

States:AnyLabels:AnyRewards:Any

Outputs

Policy:AnyActions:AnyReward Trace:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
algorithmselectepsilon_greedy_qepsilon_greedy_q is linear Q with ε exploration · linucb adds an optimism bonus and is usually strongest here · reinforce is a linear policy gradient
epsilonfloat0.1Exploration rate for epsilon_greedy_q
learning_ratefloat0.1Fraction of the normalised-LMS step to the exact fit, over z-scored states
alpha_ucbfloat1Confidence-bonus width for linucb
n_passesint3Passes over the stream, each in a fresh shuffled order
reward_correctfloat1Simulated reward for the right action, when Rewards is not wired
reward_incorrectfloat-1Simulated reward for a wrong one
seedint0—

Offline Policy Trainer

Reinforcement Learning (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Learns a policy from LOGGED interactions with no ability to try anything new — the setting every retrospective BCI dataset is in. Behaviour cloning reproduces the logging policy and ignores the rewards, which is the honest baseline; conservative_q adds the CQL penalty that pushes down the value of actions the log never took in that state, which is the whole reason offline RL fails without it. The evaluation is the hard part: 'what would the new policy have earned' is an importance-weighted average whose variance explodes when the new policy disagrees with the logging one. So the block reports the effective sample size (Kish's, routinely single digits) and a bootstrap confidence interval beside the estimate, and declares the estimate unusable when it collapses. Without logged propensities it substitutes the empirical action frequency and says loudly that every off-policy number is then biased.

Inputs

States:AnyLogged Actions:AnyLogged Rewards:AnyPropensities:Any

Outputs

Policy:AnyActions:AnyQ Values:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
methodselectbehaviour_cloningbehaviour_cloning reproduces the log · conservative_q is fitted Q with the CQL penalty · importance_weighted reweights by inverse propensity
conservative_weightfloat1CQL penalty strength — higher keeps the policy closer to the log, which is what makes its evaluation trustworthy
learning_ratefloat0.05Step size
n_epochsint200Full-batch passes
clip_weightfloat10Importance-weight cap. Uncapped weights make the estimate a single row
min_effective_sampleint30Below this the estimate is reported but declared unusable
seedint0—

Multi-Agent Arena

Reinforcement Learning (BCILattice)ML SuiteWorkflow DesignerFunction (custom)

Several policies acting on the same stream with an arbiter, and the question that makes it worth having: does the group beat its best member? Reports per-agent reward, the joint reward, the lift over the best single agent, and the mean pairwise agreement — because combining policies pays only when they make DIFFERENT mistakes, and agents that agree on 95% of steps are one policy with different seeds. The reward-weighted and best-agent arbiters judge on a recent window rather than the whole history, so they can notice an agent that became the good one halfway through the session.

Inputs

Agents:AnyLabels:AnyRewards:Any

Outputs

Joint Actions:AnyPer-Agent Actions:AnyMetrics:AnyProvenance:AnyLogs:Any

Settings

SettingTypeDefaultDescription
arbiterselectmajoritymajority is a vote over hard choices · confidence lets the most peaked agent decide each step · reward_weighted blends scores by recent reward · best_agent defers to the current leader
reward_correctfloat1Simulated reward for the right action, when Rewards is not wired
reward_incorrectfloat-1Simulated reward for a wrong one
windowint50Recent steps the reward-weighted and best-agent arbiters judge on
seedint0—

Need a library that is not on this page? Extensions covers turning any Python package — Cedalion, or anything on the curated shelf — into blocks that wire into these same canvases.

BCILattice Advanced Blocks v1.0 · BCINexus Platform · 2026-05-20