Skip to content
New issue

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

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

Already on GitHub? # to your account

FilterNet: Changing the location of nondominant filter also changes the location of dominant filter in class "TwoSubfieldLinearCell" of "cellmodel.py" in bmtk #339

Open
CloudyDory opened this issue Nov 7, 2023 · 2 comments

Comments

@CloudyDory
Copy link

CloudyDory commented Nov 7, 2023

Overview

In function default_cell_loader() of "bmtk/simulator/filternet/default_setters/cell_loaders.py", variable linear_filter_son (line 121) and linear_filter_soff (line 124) take the same variable spatial_filter as input. This causes the two former variables to store the same spatial_filter object.

Then, linear_filter_son and linear_filter_soff are passed into the __init__() function of "bmtk/simulator/filternet/lgnmodel/cellmodel.py" as argument dominant_filterand nondominant_filter. However, in line 65-69 of this file:

self.dominant_filter.spatial_filter.translate = self.dominant_subfield_location
hor_offset = np.cos(self.onoff_axis_angle*np.pi/180.)*self.subfield_separation + self.dominant_subfield_location[0]
vert_offset = np.sin(self.onoff_axis_angle*np.pi/180.)*self.subfield_separation + self.dominant_subfield_location[1]
rel_translation = (hor_offset, vert_offset)
self.nondominant_filter.spatial_filter.translate = rel_translation

the intention is to set a different location for the nondominant_filter. But since self.dominant_filter.spatial_filter and self.nondominant_filter.spatial_filter is actually the same object, changing self.nondominant_filter.spatial_filter.translate will also change self.dominant_filter.spatial_filter.translate.

Therefore, when running the LGN filternet, the dominant and nondominant spatial filter will be placed at exactly the same location. This can be verified by checking the lnunit_cursor_list in class SeparableMultiLNUnitCursor of "bmtk/simulator/filternet/lgnmodel/cursor.py".

Steps to reproduce

  1. Download and extract the attachment (1 MB) in this issue. The files are selected from the source code of the mouse V1 model in Billeh et al., Neuron, 2020 (mostly unmodified).
  2. Set a breakpoint at line 69 of "bmtk/simulator/filternet/lgnmodel/cellmodel.py". This file runs when establishing the network.
  3. Run and debug "run_filternet.py", wait until it stops at the above breakpoint.
  4. Print self.dominant_filter.spatial_filter.translate, the result should be: (8.07545259102928, 10.021859654121696)
  5. Run line 69 of "bmtk/simulator/filternet/lgnmodel/cellmodel.py".
  6. Print self.dominant_filter.spatial_filter.translate and self.nondominant_filter.spatial_filter.translate, the outputs will both be (3.6379139789913113, 6.169332828582764). THIS IS THE BUG
  7. Print self.dominant_filter.spatial_filter.translate is self.nondominant_filter.spatial_filter.translate, the output will be True.
  8. Remove the breakpoint in line 69 of "bmtk/simulator/filternet/lgnmodel/cellmodel.py", set a new breakpoint in line 210 of "bmtk/simulator/filternet/lgnmodel/cursor.py". This file runs when actually simulating the network.
  9. Continue running the code until it stops at the new breakpoint (make take several minutes).
  10. Print self.lnunit_cursor_list[0].spatial_filter.translate, self.lnunit_cursor_list[1].spatial_filter.translate. The output is ((3.6379139789913113, 6.169332828582764), (3.6379139789913113, 6.169332828582764)).
  11. Print np.abs(self.lnunit_cursor_list[0].spatial_filter.get_kernel(np.arange(120), np.arange(240)).full()).argmax(), np.abs(self.lnunit_cursor_list[1].spatial_filter.get_kernel(np.arange(120), np.arange(240)).full()).argmax(). The output is (1444, 1444), which shows that the two spatial kernels peak at the same location.

Suggested fix

Use copy.deepcopy to isolate the two spatial_filter in function default_cell_loader() of "bmtk/simulator/filternet/default_setters/cell_loaders.py".

Attached code

attached_code.zip

@CloudyDory CloudyDory changed the title Changing the location of nondominant filter also changes the location of dominant filter in class "TwoSubfieldLinearCell" of "cellmodel.py" in bmtk FilterNet: Changing the location of nondominant filter also changes the location of dominant filter in class "TwoSubfieldLinearCell" of "cellmodel.py" in bmtk Nov 7, 2023
shixnya added a commit to shixnya/bmtk that referenced this issue Nov 8, 2023
shixnya added a commit to shixnya/bmtk that referenced this issue Nov 8, 2023
@shixnya
Copy link
Collaborator

shixnya commented Nov 8, 2023

Hi CloudyDory,

Thank you for the very detailed issue report. I reproduced the bug and we are working towards fixing it.

Best,
Shinya

shixnya added a commit that referenced this issue Nov 8, 2023
Before the fix, spatial filters for ON and OFF receptive fields were pointing to the same object. Resolved by creating filter objects separately.
@CloudyDory
Copy link
Author

CloudyDory commented Nov 9, 2023

@shixnya Thank you for the fix! Can you also take a look at issue #337 ? The bmtk code saves the dominant_filter amplitude for the nondominant_filter, which also looks strange.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants