brainscore-language 2.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- brainscore_language/__init__.py +80 -0
- brainscore_language/__main__.py +14 -0
- brainscore_language/artificial_subject.py +140 -0
- brainscore_language/benchmark_helpers/__init__.py +47 -0
- brainscore_language/benchmarks/blank2014/__init__.py +4 -0
- brainscore_language/benchmarks/blank2014/benchmark.py +50 -0
- brainscore_language/benchmarks/blank2014/ceiling.py +204 -0
- brainscore_language/benchmarks/blank2014/test.py +75 -0
- brainscore_language/benchmarks/fedorenko2016/__init__.py +5 -0
- brainscore_language/benchmarks/fedorenko2016/benchmark.py +56 -0
- brainscore_language/benchmarks/futrell2018/__init__.py +4 -0
- brainscore_language/benchmarks/futrell2018/__pycache__/__init__.cpython-311.pyc +0 -0
- brainscore_language/benchmarks/futrell2018/__pycache__/benchmark.cpython-311.pyc +0 -0
- brainscore_language/benchmarks/futrell2018/benchmark.py +90 -0
- brainscore_language/benchmarks/futrell2018/test.py +43 -0
- brainscore_language/benchmarks/pereira2018/__init__.py +5 -0
- brainscore_language/benchmarks/pereira2018/benchmark.py +101 -0
- brainscore_language/benchmarks/pereira2018/ceiling_packaging.py +268 -0
- brainscore_language/benchmarks/pereira2018/test.py +88 -0
- brainscore_language/benchmarks/syntaxgym/README.md +79 -0
- brainscore_language/benchmarks/syntaxgym/__init__.py +71 -0
- brainscore_language/benchmarks/syntaxgym/benchmark.py +172 -0
- brainscore_language/benchmarks/syntaxgym/gpt2_precomputed.py +1131 -0
- brainscore_language/benchmarks/syntaxgym/requirements.txt +2 -0
- brainscore_language/benchmarks/syntaxgym/sg_prediction.py +234 -0
- brainscore_language/benchmarks/syntaxgym/sg_suite.py +192 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/center_embed.json +2014 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/center_embed_mod.json +2239 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/cleft.json +4865 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/cleft_modifier.json +5506 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/fgd_hierarchy.json +6056 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/fgd_object.json +3699 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/fgd_pp.json +3699 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/fgd_subject.json +3699 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/mvrr.json +3413 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/mvrr_mod.json +3862 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/npi_orc_any.json +6450 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/npi_orc_ever.json +6450 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/npi_src_any.json +6450 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/npi_src_ever.json +6450 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/npz_ambig.json +2929 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/npz_ambig_mod.json +3314 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/npz_obj.json +2929 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/npz_obj_mod.json +3314 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/number_orc.json +2934 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/number_prep.json +2629 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/number_src.json +2934 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/reflexive_orc_fem.json +2934 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/reflexive_orc_masc.json +2934 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/reflexive_prep_fem.json +2629 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/reflexive_prep_masc.json +2629 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/reflexive_src_fem.json +2934 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/reflexive_src_masc.json +2934 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/subordination.json +1701 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/subordination_orc-orc.json +2439 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/subordination_pp-pp.json +2439 -0
- brainscore_language/benchmarks/syntaxgym/suites/syntaxgym-2020/subordination_src-src.json +2439 -0
- brainscore_language/benchmarks/syntaxgym/test.py +94 -0
- brainscore_language/benchmarks/syntaxgym/test_suites.json +33 -0
- brainscore_language/benchmarks/tuckute2024/__init__.py +7 -0
- brainscore_language/benchmarks/tuckute2024/benchmark.py +57 -0
- brainscore_language/benchmarks/wikitext_next_word/__init__.py +4 -0
- brainscore_language/benchmarks/wikitext_next_word/benchmark.py +65 -0
- brainscore_language/benchmarks/wikitext_next_word/test.py +25 -0
- brainscore_language/data/blank2014/__init__.py +22 -0
- brainscore_language/data/blank2014/data_packaging.py +508 -0
- brainscore_language/data/blank2014/test.py +28 -0
- brainscore_language/data/fedorenko2010_localization/__init__.py +34 -0
- brainscore_language/data/fedorenko2010_localization/langloc_fmri_run1_stim_set1.csv +49 -0
- brainscore_language/data/fedorenko2010_localization/langloc_fmri_run1_stim_set2.csv +49 -0
- brainscore_language/data/fedorenko2010_localization/langloc_fmri_run1_stim_set3.csv +49 -0
- brainscore_language/data/fedorenko2010_localization/langloc_fmri_run1_stim_set4.csv +49 -0
- brainscore_language/data/fedorenko2010_localization/langloc_fmri_run1_stim_set5.csv +49 -0
- brainscore_language/data/fedorenko2010_localization/langloc_fmri_run2_stim_set1.csv +49 -0
- brainscore_language/data/fedorenko2010_localization/langloc_fmri_run2_stim_set2.csv +49 -0
- brainscore_language/data/fedorenko2010_localization/langloc_fmri_run2_stim_set3.csv +49 -0
- brainscore_language/data/fedorenko2010_localization/langloc_fmri_run2_stim_set4.csv +49 -0
- brainscore_language/data/fedorenko2010_localization/langloc_fmri_run2_stim_set5.csv +49 -0
- brainscore_language/data/fedorenko2016/__init__.py +23 -0
- brainscore_language/data/fedorenko2016/data_packaging.py +114 -0
- brainscore_language/data/fedorenko2016/test.py +14 -0
- brainscore_language/data/futrell2018/__init__.py +27 -0
- brainscore_language/data/futrell2018/__pycache__/__init__.cpython-311.pyc +0 -0
- brainscore_language/data/futrell2018/data_packaging.py +133 -0
- brainscore_language/data/futrell2018/test.py +19 -0
- brainscore_language/data/pereira2018/__init__.py +27 -0
- brainscore_language/data/pereira2018/data_packaging.py +171 -0
- brainscore_language/data/pereira2018/test.py +26 -0
- brainscore_language/data/tuckute2024/__init__.py +18 -0
- brainscore_language/data/tuckute2024/data_packaging.py +138 -0
- brainscore_language/data/tuckute2024/test.py +24 -0
- brainscore_language/data/wikitext/__init__.py +12 -0
- brainscore_language/data/wikitext/requirements.txt +1 -0
- brainscore_language/data/wikitext/test.py +11 -0
- brainscore_language/metrics/accuracy/__init__.py +4 -0
- brainscore_language/metrics/accuracy/metric.py +15 -0
- brainscore_language/metrics/accuracy/test.py +23 -0
- brainscore_language/metrics/cka/__init__.py +4 -0
- brainscore_language/metrics/cka/metric.py +111 -0
- brainscore_language/metrics/linear_predictivity/__init__.py +5 -0
- brainscore_language/metrics/linear_predictivity/metric.py +184 -0
- brainscore_language/metrics/linear_predictivity/requirements.txt +1 -0
- brainscore_language/metrics/linear_predictivity/test.py +62 -0
- brainscore_language/metrics/pearson_correlation/__init__.py +4 -0
- brainscore_language/metrics/pearson_correlation/__pycache__/__init__.cpython-311.pyc +0 -0
- brainscore_language/metrics/pearson_correlation/__pycache__/metric.cpython-311.pyc +0 -0
- brainscore_language/metrics/pearson_correlation/metric.py +18 -0
- brainscore_language/metrics/pearson_correlation/requirements.txt +1 -0
- brainscore_language/metrics/pearson_correlation/test.py +26 -0
- brainscore_language/metrics/rdm/__init__.py +13 -0
- brainscore_language/metrics/rdm/metric.py +106 -0
- brainscore_language/model_helpers/__init__.py +1 -0
- brainscore_language/model_helpers/container.py +329 -0
- brainscore_language/model_helpers/embedding.py +132 -0
- brainscore_language/model_helpers/huggingface.py +326 -0
- brainscore_language/model_helpers/localize.py +171 -0
- brainscore_language/model_helpers/modeling_suma.py +1176 -0
- brainscore_language/model_helpers/preprocessing.py +24 -0
- brainscore_language/models/earley_parser/__init__.py +4 -0
- brainscore_language/models/earley_parser/parser.py +322 -0
- brainscore_language/models/earley_parser/requirements.txt +1 -0
- brainscore_language/models/earley_parser/test.py +267 -0
- brainscore_language/models/earley_parser/treebank/sample_treebank +11 -0
- brainscore_language/models/earley_parser/utils.py +162 -0
- brainscore_language/models/glove/__init__.py +4 -0
- brainscore_language/models/glove/model.py +38 -0
- brainscore_language/models/glove/test.py +19 -0
- brainscore_language/models/gpt/__init__.py +33 -0
- brainscore_language/models/gpt/__pycache__/__init__.cpython-311.pyc +0 -0
- brainscore_language/models/gpt/test.py +77 -0
- brainscore_language/models/lm1b/__init__.py +406 -0
- brainscore_language/models/lm1b/data_utils.py +152 -0
- brainscore_language/models/lm1b/requirements.txt +1 -0
- brainscore_language/models/lm1b/test.py +67 -0
- brainscore_language/models/random_embedding/__init__.py +35 -0
- brainscore_language/models/random_embedding/test.py +52 -0
- brainscore_language/models/rnng/__init__.py +63 -0
- brainscore_language/models/rnng/test.py +30 -0
- brainscore_language/models/rnnlm/__init__.py +12 -0
- brainscore_language/models/rnnlm/test.py +58 -0
- brainscore_language/models/suma/__init__.py +30 -0
- brainscore_language/submission/__init__.py +0 -0
- brainscore_language/submission/config.py +7 -0
- brainscore_language/submission/endpoints.py +59 -0
- brainscore_language/utils/__init__.py +17 -0
- brainscore_language/utils/ceiling.py +17 -0
- brainscore_language/utils/s3.py +42 -0
- brainscore_language/utils/transformations.py +248 -0
- brainscore_language/utils/xarray.py +54 -0
- brainscore_language-2.1.0.dist-info/METADATA +87 -0
- brainscore_language-2.1.0.dist-info/RECORD +154 -0
- brainscore_language-2.1.0.dist-info/WHEEL +5 -0
- brainscore_language-2.1.0.dist-info/licenses/LICENSE +21 -0
- brainscore_language-2.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from typing import Dict, Any, Union, Callable
|
|
2
|
+
|
|
3
|
+
from brainio.assemblies import DataAssembly
|
|
4
|
+
from brainscore_core.benchmarks import Benchmark
|
|
5
|
+
from brainscore_core.metrics import Score, Metric
|
|
6
|
+
from brainscore_core.plugin_management.conda_score import wrap_score
|
|
7
|
+
from brainscore_core.plugin_management.import_plugin import import_plugin
|
|
8
|
+
from brainscore_language.artificial_subject import ArtificialSubject
|
|
9
|
+
|
|
10
|
+
data_registry: Dict[str, Callable[[], Union[DataAssembly, Any]]] = {}
|
|
11
|
+
""" Pool of available data """
|
|
12
|
+
|
|
13
|
+
metric_registry: Dict[str, Callable[[], Metric]] = {}
|
|
14
|
+
""" Pool of available metrics """
|
|
15
|
+
|
|
16
|
+
benchmark_registry: Dict[str, Callable[[], Benchmark]] = {}
|
|
17
|
+
""" Pool of available benchmarks """
|
|
18
|
+
|
|
19
|
+
model_registry: Dict[str, Callable[[], ArtificialSubject]] = {}
|
|
20
|
+
""" Pool of available models """
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def load_dataset(identifier: str) -> Union[DataAssembly, Any]:
|
|
24
|
+
import_plugin('brainscore_language', 'data', identifier)
|
|
25
|
+
|
|
26
|
+
return data_registry[identifier]()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def load_metric(identifier: str, *args, **kwargs) -> Metric:
|
|
30
|
+
import_plugin('brainscore_language', 'metrics', identifier)
|
|
31
|
+
|
|
32
|
+
return metric_registry[identifier](*args, **kwargs)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def load_benchmark(identifier: str) -> Benchmark:
|
|
36
|
+
import_plugin('brainscore_language', 'benchmarks', identifier)
|
|
37
|
+
|
|
38
|
+
return benchmark_registry[identifier]()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def load_model(identifier: str) -> ArtificialSubject:
|
|
42
|
+
import_plugin('brainscore_language', 'models', identifier)
|
|
43
|
+
|
|
44
|
+
model = model_registry[identifier]()
|
|
45
|
+
model.identifier = identifier
|
|
46
|
+
|
|
47
|
+
return model
|
|
48
|
+
|
|
49
|
+
def _run_score(model_identifier: str, benchmark_identifier: str) -> Score:
|
|
50
|
+
"""
|
|
51
|
+
Score the model referenced by the `model_identifier` on the benchmark referenced by the `benchmark_identifier`.
|
|
52
|
+
"""
|
|
53
|
+
model: ArtificialSubject = load_model(model_identifier)
|
|
54
|
+
benchmark: Benchmark = load_benchmark(benchmark_identifier)
|
|
55
|
+
score: Score = benchmark(model)
|
|
56
|
+
score.attrs['model_identifier'] = model_identifier
|
|
57
|
+
score.attrs['benchmark_identifier'] = benchmark_identifier
|
|
58
|
+
return score
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def score(model_identifier: str, benchmark_identifier: str, conda_active: bool=False) -> Score:
|
|
62
|
+
"""
|
|
63
|
+
Score the model referenced by the `model_identifier` on the benchmark referenced by the `benchmark_identifier`.
|
|
64
|
+
The model needs to implement the :class:`~brainscore_language.artificial_subject.ArtificialSubject` interface
|
|
65
|
+
so that the benchmark can interact with it.
|
|
66
|
+
The benchmark will be looked up from the :data:`~brainscore_language.benchmarks` and evaluates the model
|
|
67
|
+
(looked up from :data:`~brainscore_language.models`) on how brain-like it is under that benchmark's
|
|
68
|
+
experimental paradigm, primate measurements, comparison metric, and ceiling.
|
|
69
|
+
This results in a quantitative
|
|
70
|
+
`Score <https://brain-score-core.readthedocs.io/en/latest/modules/metrics.html#brainscore_core.metrics.Score>`_
|
|
71
|
+
ranging from 0 (least brain-like) to 1 (most brain-like under this benchmark).
|
|
72
|
+
|
|
73
|
+
:param model_identifier: the identifier for the model
|
|
74
|
+
:param benchmark_identifier: the identifier for the benchmark to test the model against
|
|
75
|
+
:return: a Score of how brain-like the candidate model is under this benchmark. The score is normalized by
|
|
76
|
+
this benchmark's ceiling such that 1 means the model matches the data to ceiling level.
|
|
77
|
+
"""
|
|
78
|
+
return wrap_score(__file__,
|
|
79
|
+
model_identifier=model_identifier, benchmark_identifier=benchmark_identifier,
|
|
80
|
+
score_function=_run_score, conda_active=conda_active)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import fire
|
|
4
|
+
|
|
5
|
+
from brainscore_language import score as _score_function
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def score(model_identifier: str, benchmark_identifier: str, conda_active: bool=False):
|
|
9
|
+
result = _score_function(model_identifier, benchmark_identifier, conda_active)
|
|
10
|
+
print(result) # print instead of return because fire has issues with xarray objects
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
if __name__ == '__main__':
|
|
14
|
+
fire.Fire()
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from typing import Dict, List, Union
|
|
2
|
+
|
|
3
|
+
from brainio.assemblies import DataAssembly
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ArtificialSubject:
|
|
7
|
+
def identifier(self) -> str:
|
|
8
|
+
"""
|
|
9
|
+
The unique identifier for this model.
|
|
10
|
+
|
|
11
|
+
:return: e.g. `'glove'`, or `'distilgpt2'`
|
|
12
|
+
"""
|
|
13
|
+
raise NotImplementedError()
|
|
14
|
+
|
|
15
|
+
class Task:
|
|
16
|
+
""" task to perform """
|
|
17
|
+
# ideally we would define these as enums (also for RecordingTarget and RecordingType)
|
|
18
|
+
# but accessing enums gives weird Enum objects whereas this setup just gives a string
|
|
19
|
+
|
|
20
|
+
next_word = 'next_word'
|
|
21
|
+
"""
|
|
22
|
+
Predict the next word from the preceding context. Output a :class:`~brainio.assemblies.BehavioralAssembly` with
|
|
23
|
+
next-word predictions as the values and preceding stimulus in the `stimulus` coordinate.
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
|
|
27
|
+
Calling `digest_text(text = 'the quick brown')` could output
|
|
28
|
+
|
|
29
|
+
.. code-block:: python
|
|
30
|
+
|
|
31
|
+
{'behavior': <xarray.BehavioralAssembly (presentation: 1)>
|
|
32
|
+
array(['fox']), # the actual next word
|
|
33
|
+
Coordinates:
|
|
34
|
+
* presentation (presentation) MultiIndex
|
|
35
|
+
- stimulus (presentation) object 'the quick brown'
|
|
36
|
+
- stimulus_id (presentation) int64 0}
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
|
|
40
|
+
Calling `digest_text(text = ['the quick brown', 'fox jumps', 'over the lazy'])` could output
|
|
41
|
+
|
|
42
|
+
.. code-block:: python
|
|
43
|
+
|
|
44
|
+
{'behavior': <xarray.BehavioralAssembly (presentation: 3)>
|
|
45
|
+
array(['fox', 'over', 'dog']), # the actual next words
|
|
46
|
+
Coordinates:
|
|
47
|
+
* presentation (presentation) MultiIndex
|
|
48
|
+
- stimulus (presentation) object 'the quick brown' 'fox jumps', 'over the lazy'
|
|
49
|
+
- stimulus_id (presentation) int64 0 1 2}
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
reading_times = 'reading_times'
|
|
53
|
+
"""
|
|
54
|
+
Output how long it took to read a given text, in milliseconds.
|
|
55
|
+
Output a :class:`~brainio.assemblies.BehavioralAssembly` with reading times in milliseconds as the values and
|
|
56
|
+
text in the `stimulus` coordinate.
|
|
57
|
+
|
|
58
|
+
Example:
|
|
59
|
+
|
|
60
|
+
Calling `digest_text(text = 'the quick brown')` could output
|
|
61
|
+
|
|
62
|
+
.. code-block:: python
|
|
63
|
+
|
|
64
|
+
{'behavior': <xarray.BehavioralAssembly (presentation: 1)>
|
|
65
|
+
array([329.15]), # reading time in milliseconds
|
|
66
|
+
Coordinates:
|
|
67
|
+
* presentation (presentation) MultiIndex
|
|
68
|
+
- stimulus (presentation) object 'the quick brown'
|
|
69
|
+
- stimulus_id (presentation) int64 0}
|
|
70
|
+
|
|
71
|
+
Example:
|
|
72
|
+
|
|
73
|
+
Calling `digest_text(text = ['the quick brown', 'fox jumps', 'over the lazy'])` could output
|
|
74
|
+
|
|
75
|
+
.. code-block:: python
|
|
76
|
+
|
|
77
|
+
{'behavior': <xarray.BehavioralAssembly (presentation: 3)>
|
|
78
|
+
array([329.15, 337.53, 341.13]), # reading times in milliseconds
|
|
79
|
+
Coordinates:
|
|
80
|
+
* presentation (presentation) MultiIndex
|
|
81
|
+
- stimulus (presentation) object 'the quick brown' 'fox jumps', 'over the lazy'
|
|
82
|
+
- stimulus_id (presentation) int64 0 1 2}
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
def start_behavioral_task(self, task: Task):
|
|
86
|
+
"""
|
|
87
|
+
Instruct the subject to output behavior when queried with
|
|
88
|
+
:meth:`~brainscore_language.artificial_subject.ArtificialSubject.digest_text`. Calling
|
|
89
|
+
:meth:`~brainscore_language.artificial_subject.ArtificialSubject.digest_text` will then output a
|
|
90
|
+
:class:`~brainio.assemblies.BehavioralAssembly` in the `'behavior'` part of the output dict.
|
|
91
|
+
|
|
92
|
+
:param task: Which :class:`~brainscore_language.artificial_subject.ArtificialSubject.Task` to use.
|
|
93
|
+
"""
|
|
94
|
+
raise NotImplementedError()
|
|
95
|
+
|
|
96
|
+
class RecordingTarget:
|
|
97
|
+
""" location to record from """
|
|
98
|
+
language_system = "language_system"
|
|
99
|
+
language_system_left_hemisphere = "language_system_left_hemisphere"
|
|
100
|
+
language_system_right_hemisphere = "language_system_right_hemisphere"
|
|
101
|
+
|
|
102
|
+
class RecordingType:
|
|
103
|
+
""" method of recording """
|
|
104
|
+
|
|
105
|
+
fMRI = "fMRI"
|
|
106
|
+
""" functional magnetic resonance imaging """
|
|
107
|
+
ECoG = "ECoG"
|
|
108
|
+
""" Electrocorticography """
|
|
109
|
+
|
|
110
|
+
def start_neural_recording(self, recording_target: RecordingTarget, recording_type: RecordingType):
|
|
111
|
+
"""
|
|
112
|
+
Begin neural recordings from this subject. Calling
|
|
113
|
+
:meth:`~brainscore_language.artificial_subject.ArtificialSubject.digest_text` will then output a
|
|
114
|
+
:class:`~brainio.assemblies.NeuroidAssembly` in the `'neural'` part of the output dict.
|
|
115
|
+
|
|
116
|
+
:param recording_target: where in the language-involved parts of the brain to record from.
|
|
117
|
+
:param recording_type: What recording method should be used.
|
|
118
|
+
"""
|
|
119
|
+
raise NotImplementedError()
|
|
120
|
+
|
|
121
|
+
def digest_text(self, text: Union[str, List[str]]) -> Dict[str, DataAssembly]:
|
|
122
|
+
"""
|
|
123
|
+
:param text: text to pass to the subject, either a single string (e.g. `"the quick brown fox jumped"`),
|
|
124
|
+
or a list of strings (e.g. `["the quick", "brown fox jumped"]`)
|
|
125
|
+
:return: a dictionary mapping from `'behavior'` and `'neural'` to a :class:`~brainio.assemblies.DataAssembly`,
|
|
126
|
+
if the subject was instructed to
|
|
127
|
+
:meth:`~brainscore_language.artificial_subject.ArtificialSubject.start_behavioral_task` and/or
|
|
128
|
+
:meth:`~brainscore_language.artificial_subject.ArtificialSubject.start_neural_recording` respectively.
|
|
129
|
+
The :class:`~brainio.assemblies.DataAssembly` always contains a `presentation` dimension, corresponding to
|
|
130
|
+
the presentation of text stimuli (including a `stimulus` coordinate for the text,
|
|
131
|
+
and a `stimulus_id` coordinate that uniquely identifies each stimulus).
|
|
132
|
+
Values along the `presentation` dimension are ordered in the same way as the input.
|
|
133
|
+
The `behavior` output has no other dimension, while the `neural` output has a `neuroid` dimension
|
|
134
|
+
(including a `neuroid_id` coordinate to uniquely identify each recording unit), and sometimes a
|
|
135
|
+
`time_bin` dimension (including `time_bin_start` and `time_bin_end`).
|
|
136
|
+
Note that model state is not saved between every time that `digest_text` is called. For keeping states,
|
|
137
|
+
between different inputs, `text` should be a list.
|
|
138
|
+
|
|
139
|
+
"""
|
|
140
|
+
raise NotImplementedError()
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
from brainio.assemblies import walk_coords, array_is_element, DataAssembly
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def ci_error(samples, center, confidence=.95):
|
|
8
|
+
low, high = 100 * ((1 - confidence) / 2), 100 * (1 - ((1 - confidence) / 2))
|
|
9
|
+
confidence_below, confidence_above = np.nanpercentile(samples, low), np.nanpercentile(samples, high)
|
|
10
|
+
confidence_below, confidence_above = center - confidence_below, confidence_above - center
|
|
11
|
+
return confidence_below, confidence_above
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def manual_merge(*elements: List[DataAssembly], on='neuroid') -> DataAssembly:
|
|
15
|
+
"""
|
|
16
|
+
Manually merge a set of assemblies where xarray's automated merge might fail.
|
|
17
|
+
This function likely covers only covers a small number of use-cases, and should thus be used with caution.
|
|
18
|
+
"""
|
|
19
|
+
dims = elements[0].dims
|
|
20
|
+
assert all(element.dims == dims for element in elements[1:])
|
|
21
|
+
merge_index = dims.index(on)
|
|
22
|
+
# the coordinates in the merge index should have the same keys
|
|
23
|
+
assert _coords_match(elements, dim=on,
|
|
24
|
+
match_values=False), f"coords in {[element[on] for element in elements]} do not match"
|
|
25
|
+
# all other dimensions, their coordinates and values should already align
|
|
26
|
+
for dim in set(dims) - {on}:
|
|
27
|
+
assert _coords_match(elements, dim=dim,
|
|
28
|
+
match_values=True), f"coords in {[element[dim] for element in elements]} do not match"
|
|
29
|
+
# merge values without meta
|
|
30
|
+
merged_values = np.concatenate([element.values for element in elements], axis=merge_index)
|
|
31
|
+
# piece together with meta
|
|
32
|
+
result = type(elements[0])(merged_values, coords={
|
|
33
|
+
**{coord: (dims, values)
|
|
34
|
+
for coord, dims, values in walk_coords(elements[0])
|
|
35
|
+
if not array_is_element(dims, on)},
|
|
36
|
+
**{coord: (dims, np.concatenate([element[coord].values for element in elements]))
|
|
37
|
+
for coord, dims, _ in walk_coords(elements[0])
|
|
38
|
+
if array_is_element(dims, on)}}, dims=elements[0].dims)
|
|
39
|
+
return result
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _coords_match(elements, dim, match_values=False):
|
|
43
|
+
""" Helper method for `manual_merge` """
|
|
44
|
+
first_coords = [(key, tuple(value)) if match_values else key for _, key, value in walk_coords(elements[0][dim])]
|
|
45
|
+
other_coords = [[(key, tuple(value)) if match_values else key for _, key, value in walk_coords(element[dim])]
|
|
46
|
+
for element in elements[1:]]
|
|
47
|
+
return all(tuple(first_coords) == tuple(coords) for coords in other_coords)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import xarray as xr
|
|
2
|
+
|
|
3
|
+
from brainscore_core.benchmarks import BenchmarkBase
|
|
4
|
+
from brainscore_core.metrics import Score
|
|
5
|
+
from brainscore_language import load_dataset, load_metric
|
|
6
|
+
from brainscore_language.artificial_subject import ArtificialSubject
|
|
7
|
+
from brainscore_language.benchmarks.blank2014.ceiling import ExtrapolationCeiling
|
|
8
|
+
from brainscore_language.data.blank2014 import BIBTEX
|
|
9
|
+
from brainscore_language.utils.ceiling import ceiling_normalize
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Blank2014Linear(BenchmarkBase):
|
|
13
|
+
"""
|
|
14
|
+
Evaluate model ability to predict neural activity in human language system functional regions of interest (fROIs)
|
|
15
|
+
in response to natural stories, recorded by Blank et al. 2014.
|
|
16
|
+
Alignment of neural activity between model and human subjects is evaluated via cross-validated linear predictivity.
|
|
17
|
+
|
|
18
|
+
This benchmark builds off the Blank2014 benchmark introduced in Schrimpf et al. 2021
|
|
19
|
+
(https://www.pnas.org/doi/10.1073/pnas.2105646118), but requires the model to have committed to neural readouts
|
|
20
|
+
(e.g. "layer 41 corresponds to the language system"), rather than testing every layer separately.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self):
|
|
24
|
+
self.data = load_dataset('Blank2014.fROI')
|
|
25
|
+
self.metric = load_metric('linear_pearsonr')
|
|
26
|
+
ceiler = ExtrapolationCeiling()
|
|
27
|
+
ceiling = ceiler(assembly=self.data, metric=self.metric)
|
|
28
|
+
super(Blank2014Linear, self).__init__(
|
|
29
|
+
identifier='Blank2014-linear',
|
|
30
|
+
version=1,
|
|
31
|
+
parent='neural_language',
|
|
32
|
+
ceiling=ceiling,
|
|
33
|
+
bibtex=BIBTEX)
|
|
34
|
+
|
|
35
|
+
def __call__(self, candidate: ArtificialSubject) -> Score:
|
|
36
|
+
candidate.start_neural_recording(recording_target=ArtificialSubject.RecordingTarget.language_system,
|
|
37
|
+
recording_type=ArtificialSubject.RecordingType.fMRI)
|
|
38
|
+
stimuli = self.data['stimulus']
|
|
39
|
+
stories = self.data['story'].values
|
|
40
|
+
predictions = []
|
|
41
|
+
for story in sorted(set(stories)): # go over individual stories, sorting to keep consistency across runs
|
|
42
|
+
story_indexer = [stimulus_story == story for stimulus_story in stories]
|
|
43
|
+
story_stimuli = stimuli[story_indexer]
|
|
44
|
+
story_predictions = candidate.digest_text(story_stimuli.values)['neural']
|
|
45
|
+
story_predictions['stimulus_id'] = 'presentation', story_stimuli['stimulus_id'].values
|
|
46
|
+
predictions.append(story_predictions)
|
|
47
|
+
predictions = xr.concat(predictions, dim='presentation')
|
|
48
|
+
raw_score = self.metric(predictions, self.data)
|
|
49
|
+
score = ceiling_normalize(raw_score, self.ceiling)
|
|
50
|
+
return score
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
import logging
|
|
3
|
+
import numpy as np
|
|
4
|
+
from numpy.random import RandomState
|
|
5
|
+
from scipy.optimize import curve_fit
|
|
6
|
+
from tqdm import tqdm, trange
|
|
7
|
+
|
|
8
|
+
from brainio.assemblies import array_is_element, walk_coords, DataAssembly, merge_data_arrays
|
|
9
|
+
from brainscore_core.metrics import Score
|
|
10
|
+
from brainscore_language.benchmark_helpers import ci_error, manual_merge
|
|
11
|
+
from brainscore_language.utils import fullname
|
|
12
|
+
from brainscore_language.utils.transformations import apply_aggregate
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def v(x, v0, tau0):
|
|
16
|
+
return v0 * (1 - np.exp(-x / tau0))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ExtrapolationCeiling:
|
|
20
|
+
def __init__(self, subject_column='subject_id', extrapolation_dimension='neuroid', num_bootstraps=100):
|
|
21
|
+
self._logger = logging.getLogger(fullname(self))
|
|
22
|
+
self.subject_column = subject_column
|
|
23
|
+
self.holdout_ceiling = HoldoutSubjectCeiling(subject_column=subject_column)
|
|
24
|
+
self.extrapolation_dimension = extrapolation_dimension
|
|
25
|
+
self.num_bootstraps = num_bootstraps
|
|
26
|
+
|
|
27
|
+
def __call__(self, assembly, metric):
|
|
28
|
+
scores = self.collect(assembly=assembly, metric=metric)
|
|
29
|
+
return self.extrapolate(scores)
|
|
30
|
+
|
|
31
|
+
def collect(self, assembly, metric):
|
|
32
|
+
num_subjects = len(set(assembly[self.subject_column].values))
|
|
33
|
+
subject_subsamples = self.build_subject_subsamples(num_subjects)
|
|
34
|
+
scores = []
|
|
35
|
+
for num_subjects in tqdm(subject_subsamples, desc='num subjects'):
|
|
36
|
+
selection_combinations = self.iterate_subsets(assembly, num_subjects=num_subjects)
|
|
37
|
+
for selections, sub_assembly in tqdm(selection_combinations, desc='selections'):
|
|
38
|
+
score = self.holdout_ceiling(assembly=sub_assembly, metric=metric)
|
|
39
|
+
score = score.expand_dims('num_subjects')
|
|
40
|
+
score['num_subjects'] = [num_subjects]
|
|
41
|
+
for key, selection in selections.items():
|
|
42
|
+
expand_dim = f'sub_{key}'
|
|
43
|
+
score = score.expand_dims(expand_dim)
|
|
44
|
+
score[expand_dim] = [str(selection)]
|
|
45
|
+
scores.append(score.raw)
|
|
46
|
+
scores = Score.merge(*scores)
|
|
47
|
+
assert hasattr(scores, 'neuroid_id')
|
|
48
|
+
return scores
|
|
49
|
+
|
|
50
|
+
def build_subject_subsamples(self, num_subjects):
|
|
51
|
+
return tuple(range(2, num_subjects + 1))
|
|
52
|
+
|
|
53
|
+
def iterate_subsets(self, assembly, num_subjects):
|
|
54
|
+
subjects = set(assembly[self.subject_column].values)
|
|
55
|
+
subject_combinations = list(itertools.combinations(sorted(subjects), num_subjects))
|
|
56
|
+
for sub_subjects in subject_combinations:
|
|
57
|
+
sub_assembly = assembly[{'neuroid': [subject in sub_subjects
|
|
58
|
+
for subject in assembly[self.subject_column].values]}]
|
|
59
|
+
yield {self.subject_column: sub_subjects}, sub_assembly
|
|
60
|
+
|
|
61
|
+
def average_collected(self, scores):
|
|
62
|
+
return scores.median('neuroid')
|
|
63
|
+
|
|
64
|
+
def extrapolate(self, ceilings):
|
|
65
|
+
neuroid_ceilings, bootstrap_params, endpoint_xs = [], [], []
|
|
66
|
+
for i in trange(len(ceilings[self.extrapolation_dimension]),
|
|
67
|
+
desc=f'{self.extrapolation_dimension} extrapolations'):
|
|
68
|
+
# extrapolate per-neuroid ceiling
|
|
69
|
+
neuroid_ceiling = ceilings.isel(**{self.extrapolation_dimension: [i]})
|
|
70
|
+
extrapolated_ceiling = self.extrapolate_neuroid(neuroid_ceiling.squeeze())
|
|
71
|
+
extrapolated_ceiling = self.add_neuroid_meta(extrapolated_ceiling, neuroid_ceiling)
|
|
72
|
+
neuroid_ceilings.append(extrapolated_ceiling)
|
|
73
|
+
# also keep track of bootstrapped parameters
|
|
74
|
+
neuroid_bootstrap_params = extrapolated_ceiling.bootstrapped_params
|
|
75
|
+
neuroid_bootstrap_params = self.add_neuroid_meta(neuroid_bootstrap_params, neuroid_ceiling)
|
|
76
|
+
bootstrap_params.append(neuroid_bootstrap_params)
|
|
77
|
+
# and endpoints
|
|
78
|
+
endpoint_x = self.add_neuroid_meta(extrapolated_ceiling.endpoint_x, neuroid_ceiling)
|
|
79
|
+
endpoint_xs.append(endpoint_x)
|
|
80
|
+
# merge and add meta
|
|
81
|
+
self._logger.debug("Merging neuroid ceilings")
|
|
82
|
+
neuroid_ceilings = manual_merge(*neuroid_ceilings, on=self.extrapolation_dimension)
|
|
83
|
+
neuroid_ceilings.attrs['raw'] = ceilings
|
|
84
|
+
self._logger.debug("Merging bootstrap params")
|
|
85
|
+
bootstrap_params = manual_merge(*bootstrap_params, on=self.extrapolation_dimension)
|
|
86
|
+
neuroid_ceilings.attrs['bootstrapped_params'] = bootstrap_params
|
|
87
|
+
self._logger.debug("Merging endpoints")
|
|
88
|
+
endpoint_xs = manual_merge(*endpoint_xs, on=self.extrapolation_dimension)
|
|
89
|
+
neuroid_ceilings.attrs['endpoint_x'] = endpoint_xs
|
|
90
|
+
# aggregate
|
|
91
|
+
ceiling = self.aggregate_neuroid_ceilings(neuroid_ceilings)
|
|
92
|
+
return ceiling
|
|
93
|
+
|
|
94
|
+
def add_neuroid_meta(self, target, source):
|
|
95
|
+
target = target.expand_dims(self.extrapolation_dimension)
|
|
96
|
+
for coord, dims, values in walk_coords(source):
|
|
97
|
+
if array_is_element(dims, self.extrapolation_dimension):
|
|
98
|
+
target[coord] = dims, values
|
|
99
|
+
return target
|
|
100
|
+
|
|
101
|
+
def aggregate_neuroid_ceilings(self, neuroid_ceilings):
|
|
102
|
+
ceiling = neuroid_ceilings.median(self.extrapolation_dimension)
|
|
103
|
+
ceiling.attrs['bootstrapped_params'] = neuroid_ceilings.bootstrapped_params.median(self.extrapolation_dimension)
|
|
104
|
+
ceiling.attrs['endpoint_x'] = neuroid_ceilings.endpoint_x.median(self.extrapolation_dimension)
|
|
105
|
+
ceiling.attrs['raw'] = neuroid_ceilings
|
|
106
|
+
return ceiling
|
|
107
|
+
|
|
108
|
+
def extrapolate_neuroid(self, ceilings):
|
|
109
|
+
# figure out how many extrapolation x points we have. E.g. for Pereira, not all combinations are possible
|
|
110
|
+
subject_subsamples = list(sorted(set(ceilings['num_subjects'].values)))
|
|
111
|
+
rng = RandomState(0)
|
|
112
|
+
bootstrap_params = []
|
|
113
|
+
for bootstrap in range(self.num_bootstraps):
|
|
114
|
+
bootstrapped_scores = []
|
|
115
|
+
for num_subjects in subject_subsamples:
|
|
116
|
+
num_scores = ceilings.sel(num_subjects=num_subjects)
|
|
117
|
+
# the sub_subjects dimension creates nans, get rid of those
|
|
118
|
+
num_scores = num_scores.dropna(f'sub_{self.subject_column}')
|
|
119
|
+
assert set(num_scores.dims) == {f'sub_{self.subject_column}', 'split'} or \
|
|
120
|
+
set(num_scores.dims) == {f'sub_{self.subject_column}'}
|
|
121
|
+
# choose from subject subsets and the splits therein, with replacement for variance
|
|
122
|
+
choices = num_scores.values.flatten()
|
|
123
|
+
bootstrapped_score = rng.choice(choices, size=len(choices), replace=True)
|
|
124
|
+
bootstrapped_scores.append(np.mean(bootstrapped_score))
|
|
125
|
+
|
|
126
|
+
params = self.fit(subject_subsamples, bootstrapped_scores)
|
|
127
|
+
params = DataAssembly([params], coords={'bootstrap': [bootstrap], 'param': ['v0', 'tau0']},
|
|
128
|
+
dims=['bootstrap', 'param'])
|
|
129
|
+
bootstrap_params.append(params)
|
|
130
|
+
bootstrap_params = merge_data_arrays(bootstrap_params)
|
|
131
|
+
# find endpoint and error
|
|
132
|
+
asymptote_threshold = .0005
|
|
133
|
+
interpolation_xs = np.arange(1000)
|
|
134
|
+
ys = np.array([v(interpolation_xs, *params) for params in bootstrap_params.values
|
|
135
|
+
if not np.isnan(params).any()])
|
|
136
|
+
median_ys = np.median(ys, axis=0)
|
|
137
|
+
diffs = np.diff(median_ys)
|
|
138
|
+
end_x = np.where(diffs < asymptote_threshold)[0].min() # first x where increase smaller than threshold
|
|
139
|
+
# put together
|
|
140
|
+
center = np.median(np.array(bootstrap_params)[:, 0])
|
|
141
|
+
error_low, error_high = ci_error(ys[:, end_x], center=center)
|
|
142
|
+
score = Score(center)
|
|
143
|
+
score.attrs['error_low'] = error_low
|
|
144
|
+
score.attrs['error_high'] = error_high
|
|
145
|
+
score.attrs['raw'] = ceilings
|
|
146
|
+
score.attrs['bootstrapped_params'] = bootstrap_params
|
|
147
|
+
score.attrs['endpoint_x'] = DataAssembly(end_x)
|
|
148
|
+
return score
|
|
149
|
+
|
|
150
|
+
def fit(self, subject_subsamples, bootstrapped_scores):
|
|
151
|
+
params, pcov = curve_fit(v, subject_subsamples, bootstrapped_scores,
|
|
152
|
+
# v (i.e. max ceiling) is between 0 and 1, tau0 unconstrained
|
|
153
|
+
bounds=([0, -np.inf], [1, np.inf]))
|
|
154
|
+
return params
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class HoldoutSubjectCeiling:
|
|
158
|
+
def __init__(self, subject_column):
|
|
159
|
+
self.subject_column = subject_column
|
|
160
|
+
self._logger = logging.getLogger(fullname(self))
|
|
161
|
+
|
|
162
|
+
def __call__(self, assembly, metric):
|
|
163
|
+
subjects = set(assembly[self.subject_column].values)
|
|
164
|
+
scores = []
|
|
165
|
+
iterate_subjects = self.get_subject_iterations(subjects)
|
|
166
|
+
for subject in tqdm(iterate_subjects, desc='heldout subject'):
|
|
167
|
+
try:
|
|
168
|
+
subject_assembly = assembly[{'neuroid': [subject_value == subject
|
|
169
|
+
for subject_value in assembly[self.subject_column].values]}]
|
|
170
|
+
# run subject pool as neural candidate
|
|
171
|
+
subject_pool = subjects - {subject}
|
|
172
|
+
pool_assembly = assembly[
|
|
173
|
+
{'neuroid': [subject in subject_pool for subject in assembly[self.subject_column].values]}]
|
|
174
|
+
score = self.score(pool_assembly, subject_assembly, metric=metric)
|
|
175
|
+
# store scores
|
|
176
|
+
apply_raw = 'raw' in score.attrs and \
|
|
177
|
+
not hasattr(score.raw, self.subject_column) # only propagate if column not part of score
|
|
178
|
+
score = score.expand_dims(self.subject_column, _apply_raw=apply_raw)
|
|
179
|
+
score.__setitem__(self.subject_column, [subject], _apply_raw=apply_raw)
|
|
180
|
+
scores.append(score)
|
|
181
|
+
except NoOverlapException as e:
|
|
182
|
+
self._logger.debug(f"Ignoring no overlap {e}")
|
|
183
|
+
continue # ignore
|
|
184
|
+
except ValueError as e:
|
|
185
|
+
if "Found array with" in str(e):
|
|
186
|
+
self._logger.debug(f"Ignoring empty array {e}")
|
|
187
|
+
continue
|
|
188
|
+
else:
|
|
189
|
+
raise e
|
|
190
|
+
|
|
191
|
+
scores = Score.merge(*scores)
|
|
192
|
+
score = apply_aggregate(lambda scores: scores.mean(self.subject_column), scores)
|
|
193
|
+
score.attrs['error'] = scores.std(self.subject_column)
|
|
194
|
+
return scores
|
|
195
|
+
|
|
196
|
+
def get_subject_iterations(self, subjects):
|
|
197
|
+
return subjects # iterate over all subjects
|
|
198
|
+
|
|
199
|
+
def score(self, pool_assembly, subject_assembly, metric):
|
|
200
|
+
return metric(pool_assembly, subject_assembly)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class NoOverlapException(Exception):
|
|
204
|
+
pass
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import numpy as np
|
|
3
|
+
from numpy.random import RandomState
|
|
4
|
+
from pytest import approx
|
|
5
|
+
from typing import Callable, Union, List
|
|
6
|
+
|
|
7
|
+
from brainio.assemblies import NeuroidAssembly
|
|
8
|
+
from brainscore_language import ArtificialSubject, load_benchmark
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestBenchmark:
|
|
12
|
+
class DummyModel(ArtificialSubject):
|
|
13
|
+
def __init__(self, activity_for_text: Callable[[Union[str, List[str]]], NeuroidAssembly]):
|
|
14
|
+
self.activity_for_text = activity_for_text
|
|
15
|
+
|
|
16
|
+
def digest_text(self, stimuli):
|
|
17
|
+
neural_activity = self.activity_for_text(stimuli)
|
|
18
|
+
return {'neural': neural_activity}
|
|
19
|
+
|
|
20
|
+
def start_neural_recording(self, recording_target: ArtificialSubject.RecordingTarget,
|
|
21
|
+
recording_type: ArtificialSubject.RecordingType):
|
|
22
|
+
assert recording_target == ArtificialSubject.RecordingTarget.language_system
|
|
23
|
+
assert recording_type == ArtificialSubject.RecordingType.fMRI
|
|
24
|
+
|
|
25
|
+
def test_dummy_bad(self):
|
|
26
|
+
random_state = RandomState(0)
|
|
27
|
+
|
|
28
|
+
def activity_for_text(stimuli: Union[str, List[str]]) -> NeuroidAssembly:
|
|
29
|
+
num_stimuli = len(stimuli)
|
|
30
|
+
num_neuroids = 25
|
|
31
|
+
neural_activity = random_state.random(size=(num_stimuli, num_neuroids)) # presentation x neuroid
|
|
32
|
+
neural_activity = NeuroidAssembly(neural_activity,
|
|
33
|
+
coords={'stimulus_seq': ('presentation', np.arange(num_stimuli)),
|
|
34
|
+
'stimulus_num': ('presentation', np.arange(num_stimuli)),
|
|
35
|
+
'neuroid_id': ('neuroid', np.arange(num_neuroids)),
|
|
36
|
+
'region': ('neuroid', ['some_region'] * num_neuroids)},
|
|
37
|
+
dims=['presentation', 'neuroid'])
|
|
38
|
+
neural_activity['stimulus'] = 'presentation', stimuli # copy over
|
|
39
|
+
return neural_activity
|
|
40
|
+
|
|
41
|
+
benchmark = load_benchmark('Blank2014-linear')
|
|
42
|
+
dummy_model = TestBenchmark.DummyModel(activity_for_text=activity_for_text)
|
|
43
|
+
score = benchmark(dummy_model)
|
|
44
|
+
assert score == 0
|
|
45
|
+
|
|
46
|
+
def test_exact(self):
|
|
47
|
+
benchmark = load_benchmark('Blank2014-linear')
|
|
48
|
+
exact_data = copy.deepcopy(benchmark.data)
|
|
49
|
+
|
|
50
|
+
def activity_for_text(stimuli: Union[str, List[str]]) -> NeuroidAssembly:
|
|
51
|
+
passage_activity = exact_data[{'presentation': [
|
|
52
|
+
list(exact_data['stimulus'].values).index(stimulus) for stimulus in stimuli]}]
|
|
53
|
+
# remove stimulus_id and stimulus coordinates to not trip up benchmark
|
|
54
|
+
passage_activity = passage_activity.reset_index('presentation')
|
|
55
|
+
del passage_activity['stimulus_id']
|
|
56
|
+
passage_activity = NeuroidAssembly(passage_activity) # index
|
|
57
|
+
return passage_activity
|
|
58
|
+
|
|
59
|
+
dummy_model = TestBenchmark.DummyModel(activity_for_text=activity_for_text)
|
|
60
|
+
score = benchmark(dummy_model)
|
|
61
|
+
assert score == approx(1)
|
|
62
|
+
|
|
63
|
+
def test_ceiling(self):
|
|
64
|
+
benchmark = load_benchmark(f'Blank2014-linear')
|
|
65
|
+
ceiling = benchmark.ceiling
|
|
66
|
+
assert ceiling == approx(.21026591, abs=.0005)
|
|
67
|
+
|
|
68
|
+
def test_ceiling_raw(self):
|
|
69
|
+
benchmark = load_benchmark(f'Blank2014-linear')
|
|
70
|
+
ceiling = benchmark.ceiling
|
|
71
|
+
assert hasattr(ceiling, 'raw')
|
|
72
|
+
assert set(ceiling.raw.dims) == {'neuroid'}
|
|
73
|
+
assert ceiling.raw.median() == ceiling
|
|
74
|
+
assert hasattr(ceiling.raw, 'raw')
|
|
75
|
+
assert set(ceiling.raw.raw.dims) == {'sub_subject_id', 'num_subjects', 'split', 'neuroid'}
|