Gridcells Gridscales Are Larger Than Inputs.

by ADMIN 45 views

Introduction

Grid cells are a type of neuron found in the brain's hippocampus and play a crucial role in spatial navigation and memory. They are characterized by their grid-like firing patterns, which are thought to be generated by the interaction of multiple inputs. In this article, we will explore the relationship between grid cell inputs and their resulting grid scales.

The Problem

When attempting to estimate grid scales using a rectified cosine grid cell model, we noticed a discrepancy between the intended grid scale and the actual distance between peaks. This discrepancy was not due to any errors in the code, but rather a fundamental property of the grid cell model.

The Code

The code used to reproduce this behavior is provided below:

# Using Tom George's code for rectified cosine grid cell model

import numpy as np
import matplotlib.pyplot as plt

def rotate(vector, theta):
    """Rotates a vector anticlockwise by angle theta."""
    R = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]])
    vector_new = np.dot(R, vector)
    return vector_new

def get_vectors_between(pos1, pos2):
    """Calculates vectors between two sets of positions."""
    pos1_ = pos1.reshape(-1, 1, pos1.shape[-1])
    pos2_ = pos2.reshape(1, -1, pos2.shape[-1])
    pos1 = np.repeat(pos1_, pos2_.shape[1], axis=1)
    pos2 = np.repeat(pos2_, pos1_.shape[0], axis=0)
    vectors = pos1 - pos2
    return vectors

def get_flattened_coords(N):
    """Generates flattened coordinates for a square meshgrid."""
    x = np.arange(N)
    y = np.arange(N)
    xv, yv = np.meshgrid(x, y)
    return np.stack((xv.flatten(), yv.flatten()), axis=1)

# --- Customizable parameters ---
N = 100  # Size of the grid
gridscales = np.array([10, 20, 30, 40])  # Grid scales for each neuron
phis = [0, 0, 0,0] # Orientations (in radians) for each neuron
# --- End of customizable parameters ---


n_neurons = len(gridscales)
phase_offsets = np.ones(shape=(n_neurons, 2)) * N/2  # Centered phase offsets

width_ratio = 4 / (3 * np.sqrt(3))
w = []
for i in range(n_neurons):
    w1 = np.array([1.0, 0.0])
    w1 = rotate(w1, np.pi/6+phis[i]) # Apply orientation here, such that baseline has a peak due east
    w2 = rotate(w1, np.pi / 3)
    w3 = rotate(w1, 2 * np.pi / 3)
    w.append(np.array([w1, w2, w3]))
w = np.array(w)

pos = get_flattened_coords(N)
origin = np.ones([n_neurons, 2]) * N/2
vecs = get_vectors_between(origin, pos)

# Tile parameters for efficient calculation
w1 = np.tile(np.expand_dims(w[:, 0, :], axis=1), reps=(1, pos.shape[0], 1))
w2 = np.tile(np.expand_dims(w[:, 1, :], axis=1), reps=(1, pos.shape[0], 1))
w3 = np.tile(np.expand_dims(w[:, 2, :], axis=1), reps=(1, pos.shape[0], 1))

adjusted_gridscales = gridscales/(1.15) # THIS IS AN APPROXIMATE FIX FOR GRID SCALE CHANGING.

tiled_gridscales = np.tile(np.expand_dims(adjusted_gridscales, axis=1), reps=(1, pos.shape[0]))


phi_1 = ((2 * np.pi) / tiled_gridscales) * (vecs * w1).sum(axis=-1)
phi_2 = ((2 * np.pi) / tiled_gridscales) * (vecs * w2).sum(axis=-1)
phi_3 = ((2 * np.pi) / tiled_gridscales) * (vecs * w3).sum(axis=-1)

firingrate = (1 / 3) * (np.cos(phi_1) + np.cos(phi_2) + np.cos(phi_3))

# ... (rest of your code for firing rate calculation and plotting) ...

#calculate the firing rate at the width fraction then shift, scale and rectify at the level
a, b, c = np.array([1,0])@np.array([1,0]), np.array([np.cos(np.pi/3),np.sin(np.pi/3)])@np.array([1,0]), np.array([np.cos(np.pi/3),-np.sin(np.pi/3)])@np.array([1,0])
firing_rate_at_full_width = (1 / 3) * (np.cos(np.pi*width_ratio*a) +
                              np.cos(np.pi*width_ratio*b) +
                              np.cos(np.pi*width_ratio*c))
firing_rate_at_full_width = (1 / 3) * (2*np.cos(np.sqrt(3)*np.pi*width_ratio/2) + 1)
firingrate -= firing_rate_at_full_width
firingrate /= (1 - firing_rate_at_full_width)
firingrate[firingrate < 0] = 0

# Plotting
fig, ax = plt.subplots(1, len(gridscales), figsize=(12,4))
for i, each_cell in enumerate(gridscales):
    ax[i].imshow(firingrate[i].reshape(N, N), cmap='jet', extent=[0, N, 0, N])
    ax[i].set_title(f"Grid scale: {each_cell} \n Orientation: {phis[i]:.2f} rad")
    ax[i].axis('off')

plt.tight_layout()
plt.show()

## Computing and reporting difernences in scale
from skimage.feature import peak_local_max
for i in range(firingrate.shape[0]):
  peaks = peak_local_max(firingrate[i].reshape(N,N))
  peaks = peaks -[N/2,N/2]
  sorted_sizes = np.sort(np.linalg.norm(peaks,axis=1))
  difference = np.mean(sorted_sizes[1:7]-gridscales[i])
  print(f'Mean difference ~{round(difference,3)} from intended scale {gridscales[i]}')
  print(f'Distance from centre for inner six peaks:\n {sorted_sizes[1:7]} \n ----')

The Issue

The issue arises from the fact that the grid cell model is based on a rectified cosine function, which has a periodicity of 2Ï€. However, the grid scales are calculated using the formula tiled_gridscales = (2 * np.pi) / (vecs * w1).sum(axis=-1), which assumes a periodicity of 2Ï€. This means that the grid scales are actually larger than the intended input values.

The Fix

To fix this issue, we can simply divide the grid scales by a magic number, 1.15, before tiling the environment and summing the cosine waves. This is done in the line adjusted_gridscales = gridscales/(1.15). This fix is not ideal, as it introduces a new parameter that is not well understood, but it does seem to work in practice.

Conclusion

In conclusion, the grid cell model used in this article has a fundamental property that causes the grid scales to be larger than the intended input values. This issue can be fixed by dividing the grid scales by a magic number, 1.15, before tiling the environment and summing the cosine waves. However, this fix is not ideal, and further research is needed to fully understand the relationship between grid cell inputs and their resulting grid scales.

Future Work

Future work could involve investigating the relationship between grid cell inputs and their resulting grid scales in more detail. This could involve using different grid cell models or exploring the effects of different parameters on the grid scales. Additionally, it would be interesting to see how this issue affects the performance of grid cell-based navigation systems.

Code

The code used in this article is provided above. It is a modified version of the code used in the original article, with the fix for the grid scale issue included.

References

  • [1] Tom George. Rectified Cosine Grid Cell Model. GitHub
  • [2] RatInABox-Lab. RatInABox. GitHub

Acknowledgments

Q: What is the issue with grid cell scales?

A: The issue is that the grid cell model used in this article has a fundamental property that causes the grid scales to be larger than the intended input values.

Q: Why does this issue occur?

A: This issue occurs because the grid cell model is based on a rectified cosine function, which has a periodicity of 2Ï€. However, the grid scales are calculated using the formula tiled_gridscales = (2 * np.pi) / (vecs * w1).sum(axis=-1), which assumes a periodicity of 2Ï€. This means that the grid scales are actually larger than the intended input values.

Q: How can this issue be fixed?

A: This issue can be fixed by dividing the grid scales by a magic number, 1.15, before tiling the environment and summing the cosine waves. This is done in the line adjusted_gridscales = gridscales/(1.15).

Q: Is this fix ideal?

A: No, this fix is not ideal. It introduces a new parameter that is not well understood, and it may not work in all cases.

Q: What are the implications of this issue?

A: The implications of this issue are that the grid cell model may not be accurate in all cases. This could affect the performance of grid cell-based navigation systems.

Q: How can this issue be avoided in the future?

A: To avoid this issue in the future, it is recommended to use a grid cell model that does not have this fundamental property. Alternatively, the grid scales can be calculated using a different formula that takes into account the periodicity of the rectified cosine function.

Q: What are some potential solutions to this issue?

A: Some potential solutions to this issue include:

  • Using a different grid cell model that does not have this fundamental property.
  • Calculating the grid scales using a different formula that takes into account the periodicity of the rectified cosine function.
  • Using a different method to estimate the grid scales, such as using a machine learning algorithm.

Q: How can I reproduce this issue?

A: To reproduce this issue, you can use the code provided in the article. This code is a modified version of the code used in the original article, with the fix for the grid scale issue included.

Q: What are some potential applications of this research?

A: Some potential applications of this research include:

  • Developing more accurate grid cell-based navigation systems.
  • Understanding the neural mechanisms underlying spatial navigation.
  • Developing new methods for estimating grid scales.

Q: What are some potential limitations of this research?

A: Some potential limitations of this research include:

  • The use of a simplified grid cell model.
  • The assumption that the grid scales are calculated using a specific formula.
  • The lack of experimental data to support the findings.

Q: How can I get involved in this research?

A: If you are interested in getting involved in this research, you can contact the authors of the article or join the discussion on the GitHub repository.