Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: tests

on:
push:
branches: [main, dev]
pull_request:

jobs:
pytest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true

# bdpy declares Requires-Python <3.12.
- name: Set up Python
run: uv python install 3.11

- name: Install dependencies
run: uv sync --group dev --python 3.11

- name: Run tests
run: uv run --python 3.11 pytest
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
.venv
.ipynb_checkpoints

__pycache__/
*.py[cod]
.pytest_cache/
31 changes: 28 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,24 @@ $ python evaluation.py config/deeprecon_pyfastl2lir_alpha100_vgg19_allunits.yaml

```shell
# Training of decoding models
$ python train_decoder_sklearn_ridge.py config/deeprecon_pyfastl2lir_alpha100_vgg19_allunits.yaml
$ python train_decoder_sklearn_ridge.py config/deeprecon_sklearn_ridge_alpha100_vgg19_allunits.yaml

# Prediction of DNN features
$ python predict_feature.py config/deeprecon_pyfastl2lir_alpha100_vgg19_allunits.yaml
$ python predict_feature.py config/deeprecon_sklearn_ridge_alpha100_vgg19_allunits.yaml

# Evaluation
$ python evaluation.py config/deeprecon_pyfastl2lir_alpha100_vgg19_allunits.yaml
$ python evaluation.py config/deeprecon_sklearn_ridge_alpha100_vgg19_allunits.yaml
```

The scikit-learn Ridge decoder is trained and stored in a factorized form: the
model maps brain activity onto the training stimulus basis, and prediction
combines its coefficients with the training features. This is mathematically
identical to regressing the features directly, but the stored decoder is much
smaller and training does not scale with the feature dimension.
`predict_feature.py` therefore reads the training features
(`decoder.features.paths`, already set in the example config). See
`ridge_factorization.py` for the details.

### Cross-validation feature decoding

- Training: `cv_train_decoder_fastl2lir.py` (example for scikit-learn Ridge regression)
Expand All @@ -85,6 +94,22 @@ $ python cv_predict_feature_fastl2lir.py config/deeprecon_cv_pyfastl2lir_alpha10
$ python cv_evaluation.py config/deeprecon_cv_pyfastl2lir_alpha100_vgg19_allunits.yaml
```

### Tests

The test suite runs on small synthetic data generated on the fly; no downloaded
dataset is required.

```shell
# Install the test dependencies and run the suite
$ uv sync --group dev
$ uv run pytest
```

`tests/data/golden/` holds regression fixtures recording the numerical output of
the decoding pipeline. Regenerate them with
`uv run python -m tests.generate_golden` only when the expected output is meant
to change, and say so explicitly in the commit message.

## References

- Horikawa and Kamitani (2017) Generic decoding of seen and imagined objects using hierarchical visual features. *Nature Communications* 8:15037. https://www.nature.com/articles/ncomms15037
Expand Down
4 changes: 2 additions & 2 deletions config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ These settings are used by the decoder training script (e.g., `train_decoder_fas
- `decoder.path`: Defines the path where the decoder data is located. The path can include placeholders like `${decoder.name}` and `${decoder.features.name}` to dynamically set paths based on the feature name.
- `decoder.parameters`:
- `alpha`: A regularization parameter set to 100.
- `chunk_axis`: Indicates that chunking is done along axis 1.
- `chunk_axis`: Indicates that chunking is done along axis 1. For the sklearn Ridge decoder it applies to the prediction step only.
2. fMRI data
- This specifies fMRI data used for the decoder training.
- `decoder.fmri.name`: Refers to the dataset name, here "ImageNetTraining_fmriprep_volume_native".
Expand All @@ -27,7 +27,7 @@ These settings are used by the decoder training script (e.g., `train_decoder_fas
3. Features
- This specifies features used for the decoder training.
- `decoder.features.name`: Refers to the pre-trained DNN model used.
- `decoder.features.paths`: Provides the path to the feature data.
- `decoder.features.paths`: Provides the path to the feature data. The factorized sklearn Ridge decoder reads these at prediction time as well, as the features of the training stimuli.
- `decoder.features.layers`: Specifies the layers of the DNN from which features will be extracted.

## Decoded features
Expand Down
2 changes: 2 additions & 0 deletions config/deeprecon_sklearn_ridge_alpha100_vgg19_allunits.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ decoder:
path: ./data/feature_decoders/ImageNetTraining/${decoder.name}/${decoder.features.name}
parameters:
alpha: 100
# Axis along which the feature combination is blocked at prediction time.
chunk_axis: 1

fmri:
Expand Down Expand Up @@ -34,6 +35,7 @@ decoder:

features:
name: caffe/VGG19
# Features of the training stimuli; also read by `predict_feature.py`.
paths:
- ./data/features/ImageNetTraining/${decoder.features.name}
layers:
Expand Down
Loading