hypline encoding¶
Fit and score voxelwise ridge encoding models, the step that joins the two
sides the rest of the pipeline prepares. train maps stimulus features (X) onto
denoised BOLD (Y) per subject; analyze scores one subject's model against
another subject's brain, across production and comprehension turns. encoding
is a group of subcommands.
hypline encoding <command> <dataset-root> [OPTIONS]
| Subcommand | Does |
|---|---|
train |
Fit a per-subject ridge model from features (+ optional confounds) |
analyze |
Score a model's cross-subject predictions against a target's BOLD |
Both read from the dataset root and write to a new results/ area (see
Outputs). Results load back as live Python objects rather than flat
tables; read them for downstream analysis with the encoding results API.
The banded ridge model
Each feature becomes its own ridge band (its own regularization strength);
all confounds share one trailing band, partialled out in the same fit so a
feature cannot claim variance a confound explains. In a dyadic conversation
a subject alternates between producing speech and comprehending the
partner's, so by default train duplicates every feature and confound
regressor into a production copy and a comprehension copy and learns separate
weights for each (--no-split keeps one shared copy). Either way, two
intercept-like production/comprehension task boxcars always ride a reserved
band that absorbs the mean BOLD offset between the two states — --no-split
drops the per-regressor duplication, not this band.
hypline encoding train¶
Fit a voxelwise ridge encoding model per subject, writing one model artifact per
subject to results/.
hypline encoding train <dataset-root> \
--tasks … --features … --desc … --fold-by … [OPTIONS]
Inputs¶
- Features under
features/— the predictors, generated byfeaturegen. Named by--featuresas<kind>[-<desc>]refs; each ref becomes its own ridge band. - Confounds under
confounds/(optional) — stimulus-derived nuisance regressors, generated byconfoundgen. Named by--confounds; all share one band. Must be saved at TR level. - Denoised BOLD under
derivatives/hypline/— the target, produced bydenoise. Selected by--bold-spaceand--bold-desc(defaultdenoised).
Features are dyad-keyed and BOLD is subject-keyed, so train bridges them
through participants.tsv — see Subject vs.
dyad.
Options¶
| Option | Description | Default |
|---|---|---|
--tasks |
Comma-separated task labels to train on (e.g. neutral,opinion) — required |
— |
--features |
Comma-separated feature refs as <kind>[-<desc>] (e.g. semantic-gpt3,phonemic-noArt); each becomes its own ridge band — required |
— |
--desc |
Variant label for this model (alphanumeric); output lands under results/sub-XX/encodingModel-<desc>/ — required |
— |
--fold-by |
Cross-validation grouping axis: a BIDS entity to fold on (e.g. run), or none for a single unfolded model — required |
— |
--n-folds |
Number of folds: an integer (>=2) or loo. Required with --fold-by <entity>; omit with --fold-by none |
none |
--confounds |
Comma-separated confound refs as <kind>[-<desc>] (e.g. phonemic-onset,phonemic-rate); all share one band |
none |
--bold-space |
BOLD space to train on: fsaverage5, fsaverage6, MNI152NLin6Asym, MNI152NLin2009cAsym |
MNI152NLin2009cAsym |
--bold-desc |
BOLD desc entity selecting the input runs |
denoised |
--downsample |
Feature-to-TR downsampling: mean or sum |
mean |
--delays |
Comma-separated FIR delays in TRs | 0,1,2,3,4,5 |
--alphas |
Comma-separated ridge alphas to search | 1–1e12 log grid (13 points) |
--device |
Compute device for the fit: cpu or cuda |
cpu |
--no-split |
Fit one model over all screens instead of separate production/comprehension models | off |
--sub-ids |
Comma-separated subject IDs to train (e.g. 031,032); omit for all |
all |
--data-filters |
Comma-separated BIDS entity filters bounding the training corpus — see Segments and metadata | none |
--force |
Overwrite existing outputs (default skips them) | off |
--fold-by and --n-folds are paired
Give --n-folds when --fold-by names an entity, and omit it when
--fold-by none. Supplying one without the other raises. --fold-by none
fits a single model over the whole corpus; --fold-by run --n-folds 5 fits
five cross-validated models grouped by run.
Example¶
Fit a single model per subject from semantic features plus phonemic-timing
confounds, over the conv task:
hypline encoding train data/ \
--tasks conv \
--features semantic-gpt3 \
--confounds phonemic-onset,phonemic-rate \
--desc v1 \
--fold-by none
Cross-validate by run, five folds, on a GPU:
hypline encoding train data/ \
--tasks conv \
--features semantic-gpt3 \
--desc cv5 \
--fold-by run \
--n-folds 5 \
--device cuda
hypline encoding analyze¶
Score a trained model's predictions against a target subject's actual BOLD, per role (production / comprehension / both). Three subject roles are independent:
- model (
--model-sub) — whose trained weights are loaded. - source (
--source-sub) — whose features build the prediction inputs (X). - target (
--target-sub) — whose actual BOLD is the comparison (Y).
Any combination is valid within one study: source == target is a
within-subject fit; partners in one dyad share a conversation across different
brains; different dyads are a scramble/null control (analyze warns). The values
self and partner are accepted for --model-sub / --source-sub, resolved
relative to --target-sub via participants.tsv.
hypline encoding analyze <dataset-root> \
--target-sub … --model-sub … --model-desc … --desc … [OPTIONS]
Options¶
| Option | Description | Default |
|---|---|---|
--target-sub |
Subject whose actual BOLD and production/comprehension turns are scored against — required | — |
--model-sub |
Subject whose trained model is loaded: an ID, or self/partner (relative to --target-sub) — required |
— |
--model-desc |
The --desc passed to encoding train (its encodingModel-<desc> tag) — required |
— |
--desc |
Variant label for this eval (alphanumeric); output lands under results/sub-<target>/encodingEval-<desc>/ — required |
— |
--source-sub |
Subject whose regressors drive the prediction: an ID, or self/partner |
self |
--test-on |
Comma-separated BIDS entity filters naming which cells to score (e.g. run-6, or run-6,run-8); omit to score each model's out-of-sample cells |
out-of-sample cells |
--force |
Overwrite existing outputs (default skips them) | off |
The output is per-fold, per-band, per-role, per-voxel scores. These are himalaya
split scores — each band's own contribution to the joint prediction — so a
band's value is not a plain Pearson correlation and need not fall in [-1, 1].
Roles are derived from the target's turns: prod and comp are the
exclusive pure-production / pure-comprehension rows, and both is the union of
any speech-active row. A role with no rows scores NaN rather than zero.
Example¶
Score subject 031's own model against its own BOLD (a within-subject fit). With
default --test-on, analyze scores each model's out-of-sample cells, so the
model must be folded. A --fold-by none model trained on every cell has no
held-out cells and raises here; name cells with --test-on, or use a folded
model as below:
hypline encoding analyze data/ \
--target-sub 031 \
--model-sub self \
--model-desc cv5 \
--desc selfeval
Score subject 031's BOLD using the partner's model and features (a
cross-brain, shared-conversation eval) on run 6:
hypline encoding analyze data/ \
--target-sub 031 \
--model-sub partner \
--source-sub partner \
--model-desc v1 \
--desc crosseval \
--test-on run-6
Outputs¶
Both commands write to a new top-level results/ area, keyed by subject
(one analysis output consumes many runs across sessions, so results carry no
source-run or session entity):
<dataset-root>/results/
├── sub-031/encodingModel-v1/
│ ├── sub-031_result-encodingModel_desc-v1.joblib # train: fitted model artifact
│ └── sub-031_result-encodingModel_desc-v1.json # provenance sidecar (greppable)
└── sub-031/encodingEval-selfeval/
└── sub-031_result-encodingEval_desc-selfeval.nc # analyze: per-voxel correlations (netCDF-4)
encodingModel-<desc>/(train) — the fitted model as a.joblibblob, plus a JSON sidecar mirroring the recipe and provenance without unpickling.encodingEval-<desc>/(analyze) — the eval as a self-describing netCDF-4 file any tool can read, carrying provenance (model_sub,source_sub,target_sub,delays,bold_space,test_on, …) in its attributes.
Common errors¶
| What you see | Cause | Fix |
|---|---|---|
give --n-folds with --fold-by <entity>, and omit it with --fold-by none |
--fold-by and --n-folds were not passed both-or-neither. |
Pass --n-folds when --fold-by names an entity; omit it with --fold-by none. |
n_folds='loo' needs >= 2 groups to fold; got 1 |
--fold-by names an entity with only one value in the training corpus, so there is nothing to leave out. |
Widen the corpus (task/filters), or fit unfolded with --fold-by none. |
n_folds=N exceeds the M group(s) found for the fold_by entity (train) |
--n-folds is larger than the number of distinct --fold-by values available. |
Lower --n-folds to at most the group count, or use loo. |
No regressor files match the given filters / No BOLD files match the given filters (train) |
--tasks, --features, --data-filters, --bold-space, or --bold-desc selected nothing. |
Confirm the features and desc-denoised BOLD exist and that the filters are not too narrow. |
empty out-of-sample set — pass test_on to name cells (analyze) |
The model was trained unfolded (--fold-by none), so it has no held-out cells to score. |
Score a folded model, or name cells explicitly with --test-on. |
test_on matched no available cells: … (analyze) |
--test-on names cells the source subject does not have. |
Check the --test-on filter against the runs/conditions that exist. |
test_on entities […] not found on any available cell … check for a typo (analyze) |
A --test-on filter uses an entity that no cell carries. |
Fix the entity name (e.g. run-6, not ses-1). |
Log warns source (…) and target (…) are different dyads (analyze) |
The model/source and target belong to different dyads — a scramble/null control. | Expected for a null control; otherwise fix --source-sub / --model-sub so they share the target's dyad. |
No subjects found |
No subjects under derivatives/fmriprep/, or --sub-ids excluded them all. |
Confirm denoised BOLD exists and that filters are not too narrow. |
Loading results in Python¶
Both commands write Python objects, not tables. Load them back for downstream
analysis with the encoding results API: load_eval for
an eval, load_artifact for a fitted model.