Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add microsaccades to Brain-Score core #492

Merged
merged 45 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
4690626
integrate –https://github.com/brain-score/model-tools/pull/75 to brai…
benlonnqvist Jan 10, 2024
26ed57a
Merge branch 'brain-score:master' into vision_microsaccades
benlonnqvist Jan 10, 2024
1fee011
retrigger
benlonnqvist Jan 15, 2024
26313aa
retrigger
benlonnqvist Jan 16, 2024
71ba207
add exception for when temp file write fails
benlonnqvist Jan 17, 2024
3ea9a9c
fix error with tf temp file management
benlonnqvist Jan 17, 2024
3203e7b
add bandaid to a DataAssembly index problem
benlonnqvist Jan 18, 2024
a2e0a15
retrigger
benlonnqvist Jan 24, 2024
c1abd95
move microsaccades to the model side
benlonnqvist Feb 6, 2024
e690b4e
update comments
benlonnqvist Feb 6, 2024
5ad9863
Merge branch 'brain-score:master' into vision_microsaccades
benlonnqvist Feb 6, 2024
e05d815
remove indexing bug
benlonnqvist Feb 7, 2024
903d3f5
Merge branch 'vision_microsaccades' of https://github.com/benlonnqvis…
benlonnqvist Feb 7, 2024
629884e
fix bug with activations.shape
benlonnqvist Feb 7, 2024
0226495
Apply suggestions from code review
benlonnqvist Feb 12, 2024
307735d
Delete brainscore_vision/data/scialom2024/__init__.py
benlonnqvist Feb 12, 2024
e13391a
address review changes
benlonnqvist Feb 16, 2024
e79fbd2
remove needless import
benlonnqvist Feb 16, 2024
a17c653
fix bug with temporary file handling test
benlonnqvist Feb 19, 2024
4887728
assume number_of_trials=1 and require_variance=False when getting sto…
benlonnqvist Feb 19, 2024
9a7368e
fix bug with access to ActivationsExtractorHelper.set_visual_degrees
benlonnqvist Feb 19, 2024
b3e08fb
move extractor calls to ModelCommitment generic
benlonnqvist Feb 19, 2024
849cc7a
add check for whether activations_model exists
benlonnqvist Feb 19, 2024
114110c
fix bug with TestVisualDegrees
benlonnqvist Feb 19, 2024
218dead
add link to BrainModel issue
benlonnqvist Feb 20, 2024
ce56473
remove shifts from stimulus set packaging
benlonnqvist Feb 20, 2024
65c658b
change link signatures
benlonnqvist Feb 20, 2024
22d2ecb
change microsaccade call signature
benlonnqvist Feb 20, 2024
2e96e73
microsaccades are now computed on both a pixel and degree basis
benlonnqvist Feb 20, 2024
926778c
Apply suggestions from code review
benlonnqvist Feb 29, 2024
f7a0340
fix outdated comments, type hints, etc.
benlonnqvist Feb 29, 2024
5a8881d
change function call to reduce repetition
benlonnqvist Mar 1, 2024
2655ecf
add kwargs to microsaccade helpers
benlonnqvist Mar 1, 2024
232f4d7
refactor microsaccade usage to their own class to improve readability
benlonnqvist Mar 1, 2024
06e4b4c
refactor microsaccade coords into MicrosaccadeHelper
benlonnqvist Mar 1, 2024
18e48ae
refactor microsaccade building
benlonnqvist Mar 1, 2024
954b4cc
change the way MultiIndex is set
benlonnqvist Mar 1, 2024
52596ac
fix tf/pytorch/keras bug with image shape calculation
benlonnqvist Mar 1, 2024
9245cb4
cv2 reshaping in translate
benlonnqvist Mar 1, 2024
ead4cee
add test for exact microsaccades
benlonnqvist Mar 1, 2024
63990cf
fix microsaccade indexing
benlonnqvist Mar 1, 2024
453a2a6
rename test to be in line with current naming
benlonnqvist Mar 4, 2024
6e92878
add require_variance to _from_paths_stored
benlonnqvist Mar 4, 2024
9a67b15
reduce unnecessarily long test times by reducing the number of trials…
benlonnqvist Mar 5, 2024
0dad5e5
Merge branch 'brain-score:master' into vision_microsaccades
benlonnqvist Mar 6, 2024
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
365 changes: 322 additions & 43 deletions brainscore_vision/model_helpers/activations/core.py

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ def __init__(self, identifier,
visual_degrees=8):
self.layers = layers
self.activations_model = activations_model
# We set the visual degrees of the ActivationsExtractorHelper here to avoid changing its signature.
# The ideal solution would be to not expose the _extractor of the activations_model here, but to change
# the signature of the ActivationsExtractorHelper. See https://github.com/brain-score/vision/issues/554
self.activations_model._extractor.set_visual_degrees(visual_degrees) # for microsaccades
self._visual_degrees = visual_degrees
# region-layer mapping
if region_layer_map is None:
Expand Down
19 changes: 14 additions & 5 deletions brainscore_vision/model_helpers/brain_transformation/neural.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,30 @@ def __init__(self, identifier, activations_model, region_layer_map, visual_degre
def identifier(self):
return self._identifier

def look_at(self, stimuli, number_of_trials=1):
def look_at(self, stimuli, number_of_trials=1, require_variance: bool = False):
"""
:param number_of_trials: An integer that determines how many repetitions of the same model performs.
benlonnqvist marked this conversation as resolved.
Show resolved Hide resolved
:param require_variance: Whether to require models to return different activations for the same stimuli or not.
For detailed information, see
:meth:`~brainscore_vision.model_helpers.activations.ActivationsExtractorHelper.__call__`,
"""
layer_regions = {}
for region in self.recorded_regions:
layers = self.region_layer_map[region]
layers = make_list(layers)
for layer in layers:
assert layer not in layer_regions, f"layer {layer} has already been assigned for {layer_regions[layer]}"
layer_regions[layer] = region
activations = self.run_activations(
stimuli, layers=list(layer_regions.keys()), number_of_trials=number_of_trials)
activations = self.run_activations(stimuli,
layers=list(layer_regions.keys()),
number_of_trials=number_of_trials,
require_variance=require_variance)
activations['region'] = 'neuroid', [layer_regions[layer] for layer in activations['layer'].values]
return activations

def run_activations(self, stimuli, layers, number_of_trials=1):
activations = self.activations_model(stimuli, layers=layers)
def run_activations(self, stimuli, layers, number_of_trials=1, require_variance=None):
activations = self.activations_model(stimuli, layers=layers, number_of_trials=number_of_trials,
require_variance=require_variance)
return activations

def start_task(self, task):
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ dependencies = [
"importlib-metadata<5", # workaround to https://github.com/brain-score/brainio/issues/28
"scikit-learn", # for metric_helpers/transformations.py cross-validation
"scipy", # for benchmark_helpers/properties_common.py
"opencv-python", # for microsaccades
"h5py",
"tqdm",
"gitpython",
Expand Down
69 changes: 69 additions & 0 deletions tests/test_model_helpers/activations/test___init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,68 @@ def test_from_image_path(model_ctr, layers, image_name, pca_components, logits):
return activations


@pytest.mark.parametrize("image_name", ['rgb.jpg', 'grayscale.png', 'grayscale2.jpg', 'grayscale_alpha.png',
'palletized.png'])
@pytest.mark.parametrize(["model_ctr", "layers"], models_layers)
@pytest.mark.parametrize("number_of_trials", [1, 5, 25])
def test_require_variance_has_shift_coords(model_ctr, layers, image_name, number_of_trials):
stimulus_paths = [os.path.join(os.path.dirname(__file__), image_name)]
activations_extractor = model_ctr()
# when using microsaccades, the ModelCommitment sets its visual angle. Since this test skips the ModelCommitment,
# we set it here manually.
activations_extractor._extractor.set_visual_degrees(8.)

activations = activations_extractor(stimuli=stimulus_paths, layers=layers, number_of_trials=number_of_trials,
require_variance=True)

assert activations is not None
assert len(activations['microsaccade_shift_x_pixels']) == number_of_trials * len(stimulus_paths)
assert len(activations['microsaccade_shift_y_pixels']) == number_of_trials * len(stimulus_paths)
assert len(activations['microsaccade_shift_x_degrees']) == number_of_trials * len(stimulus_paths)
assert len(activations['microsaccade_shift_y_degrees']) == number_of_trials * len(stimulus_paths)


@pytest.mark.parametrize("image_name", ['rgb.jpg', 'grayscale.png', 'grayscale2.jpg', 'grayscale_alpha.png',
'palletized.png'])
@pytest.mark.parametrize(["model_ctr", "layers"], models_layers)
@pytest.mark.parametrize("require_variance", [False, True])
@pytest.mark.parametrize("number_of_trials", [1, 2, 10])
def test_model_requirements(model_ctr, layers, image_name, require_variance, number_of_trials):
stimulus_paths = [os.path.join(os.path.dirname(__file__), image_name)]
activations_extractor = model_ctr()
# when using microsaccades, the ModelCommitment sets its visual angle. Since this test skips the ModelCommitment,
# we set it here manually.
activations_extractor._extractor.set_visual_degrees(8.)

activations = activations_extractor(stimuli=stimulus_paths, layers=layers,
number_of_trials=number_of_trials, require_variance=require_variance)

assert activations is not None
if require_variance:
assert len(activations['presentation']) == number_of_trials
else:
assert len(activations['presentation']) == 1


@pytest.mark.parametrize("image_name", ['rgb.jpg', 'grayscale.png', 'grayscale2.jpg', 'grayscale_alpha.png',
'palletized.png'])
@pytest.mark.parametrize(["model_ctr", "layers"], models_layers)
def test_temporary_file_handling(model_ctr, layers, image_name):
import tempfile
stimulus_paths = [os.path.join(os.path.dirname(__file__), image_name)]
activations_extractor = model_ctr()
# when using microsaccades, the ModelCommitment sets its visual angle. Since this test skips the ModelCommitment,
# we set it here manually.
activations_extractor._extractor.set_visual_degrees(8.)

activations = activations_extractor(stimuli=stimulus_paths, layers=layers, number_of_trials=2,
require_variance=True)
temp_files = [f for f in os.listdir(tempfile.gettempdir()) if f.startswith('temp') and f.endswith('.png')]

assert activations is not None
assert len(temp_files) == 0


def _build_stimulus_set(image_names):
stimulus_set = StimulusSet([{'stimulus_id': image_name, 'some_meta': image_name[::-1]}
for image_name in image_names])
Expand Down Expand Up @@ -223,6 +285,13 @@ def test_exact_activations(pca_components):
image_name='rgb.jpg', pca_components=pca_components, logits=False)
path_to_expected = Path(__file__).parent / f'alexnet-rgb-{pca_components}.nc'
expected = xr.load_dataarray(path_to_expected)

# Originally, the `stimulus_path` Index was used to index into xarrays in Brain-Score, but this was changed
# as a part of PR #492 to a MultiIndex to allow metadata to be attached to multiple repetitions of the same
# `stimulus_path`. Old .nc files need to be updated to use the `presentation` index instead of `stimulus_path`,
# and instead of changing the extant activations, this test was simply modified to simulate that.
expected = expected.rename({'stimulus_path': 'presentation'})

assert (activations == expected).all()


benlonnqvist marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
11 changes: 10 additions & 1 deletion tests/test_model_helpers/brain_transformation/test___init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
from unittest.mock import Mock

from brainscore_vision.model_helpers.brain_transformation import ModelCommitment
from brainscore_vision.model_helpers.utils import fullname


class TestVisualDegrees:
def test_standard_commitment(self):
brain_model = ModelCommitment(identifier=fullname(self), activations_model=None,
# create mock ActivationsExtractorHelper with a mock set_visual_degrees to avoid failing set_visual_degrees()
mock_extractor = Mock()
mock_extractor.set_visual_degrees = Mock()
mock_activations_model = Mock()
mock_activations_model._extractor = mock_extractor

# Initialize ModelCommitment with the mock activations_model
brain_model = ModelCommitment(identifier=fullname(self), activations_model=mock_activations_model,
layers=['dummy'])
assert brain_model.visual_degrees() == 8