OSCR

GATE: Adaptive learning with working memory by information gating in multi-lamellar hippocampal formation.

Code ↔ Paper

1 match between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 1 match
  1. [1] § 4 Methods › 4.7 Agent behavior and task performance ↔ src/lick/cs.py, lines 549–676 · score 0.52 · cross entropy loss, lr, Adam, optimizer, weighted, lick

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Python · 736 lines · 33 KB · no license · 1 match

  1. """
  2. 要让小鼠学会在哪个位置进行lick,以及是否进行lick
  3. 也可以通过调整loss权重的方式,用最大化Reward的方式,让老鼠学会是否lick
  4. 实验效果:
  5. PF更加符合实际一点点,但是还是0~0.9之间没有明显的位置场。
  6. 并且!lick行为跟老鼠的行为一模一样!! oneNote 240911
  7. 24.09.10
  8. """
  9. import os
  10. import random
  11. import time
  12. import matplotlib.pyplot as plt
  13. import numpy as np
  14. import torch
  15. import torch.nn as nn
  16. from src.tools import myplot, DecoderCS
  17. from src.lick.evidence_settings import evidence_stimu_num, evidence_stimu_duration
  18. import warnings
  19. class HPCrnn(nn.Module):
  20. def __init__(self, ts=0.1, ecnum=100, ca1num=100, ca3num=100, ca3sigma=5, tracklength=100, actnum=2):
  21. """
  22. :param ts: 时间步长,单位为秒
  23. :param ecnum: EC3 & EC5的细胞数量相同,一一对应
  24. :param ca1num:
  25. :param actnum: 模型能够采取的行动数量
  26. :param ca3sigma: 注意需要比较大(>=5),否则训练可能非常缓慢
  27. """
  28. super(HPCrnn, self).__init__()
  29. self.ts = ts # 时间步长
  30. self.ecnum = ecnum
  31. self.ca1num = ca1num
  32. self.actnum = actnum
  33. self.ca3num = ca3num
  34. self.ca3sigma = ca3sigma
  35. self.tracklength = tracklength
  36. self.ca3order = np.array(range(ca3num))
  37. self.shuffleCA3()
  38. self.ca1bias = nn.Parameter(torch.zeros(ca1num))
  39. self.ec5bias = nn.Parameter(torch.zeros(ecnum))
  40. self.wca3ca1 = nn.Parameter(torch.rand(ca3num, ca1num) * 0.01)
  41. self.wec3ca1 = nn.Parameter(torch.randn(ecnum, ca1num) * 0.01)
  42. self.wca1ec5 = nn.Parameter(torch.randn(ca1num, ecnum) * 0.01)
  43. # self.wec5ec3 = nn.Parameter(torch.rand(ecnum)*0.01) # 因为每个EC3分别对应EC5,因此实际上是单位阵,就不初始化了
  44. self.wca1act = nn.Parameter(torch.randn(ca1num, actnum) * 0.01)
  45. self.actbias = nn.Parameter(torch.zeros(actnum))
  46. nn.init.xavier_normal_(self.wca1ec5)
  47. nn.init.xavier_normal_(self.wca1act)
  48. nn.init.xavier_normal_(self.wec3ca1)
  49. def shuffleCA3(self):
  50. """
  51. 重新排布CA3的顺序,用于模仿空间remap
  52. :return:
  53. """
  54. np.random.shuffle(self.ca3order)
  55. def init_wca1act(self):
  56. self.wca1act = nn.Parameter(torch.randn(self.ca1num, self.actnum) * 0.01)
  57. nn.init.xavier_normal_(self.wca1act)
  58. self.actbias = nn.Parameter(torch.zeros(self.actnum))
  59. def getCA3output(self, x):
  60. """
  61. 根据当前的ca3排布,输出ca3的发放率
  62. :param x: 当前的位置
  63. :return: 每个ca3细胞的发放率
  64. """
  65. ca3center = torch.linspace(-0.1 * self.tracklength, 1.1 * self.tracklength, self.ca3num)
  66. ca3center = ca3center[self.ca3order]
  67. return torch.exp(-(ca3center - x) ** 2 / self.ca3sigma ** 2 / 2)
  68. def forward(self, ec3input, ec3_last, ec5_last, ca1_last, isSaveAll=False):
  69. """
  70. :param ec3input: (bs, tracklength, ecnum), 传递给所有EC3的额外输入
  71. :param ec3_last: (bs, ecnum), 继承自上一轮的信息,用于这一轮的细胞的初始化
  72. :param ec5_last:
  73. :param ca1_last: (bs, ca1num)
  74. :param isSaveAll: 是否将整个batch的history数据进行输出,用于在训练之后对模型进行测试
  75. :return:
  76. actlist: (bs, tracklength, actnum), linear输出的结果,结合crossEntropy训练
  77. ec3his: (trachlength, ecnum),本轮的EC3发放率历史,只取第一个细胞进行记录
  78. ec3: (bs, ecnum), 本轮最后ec3的发放率,可以作为下一轮epoch EC3的初始值
  79. """
  80. bs = ec3input.shape[0]
  81. assert ec3input.shape[2] == self.ecnum
  82. ec3 = ec3_last
  83. ec5 = ec5_last
  84. ca1 = ca1_last
  85. if isSaveAll:
  86. ec3his = torch.zeros(bs, self.tracklength, self.ecnum) # 注意,这里只保留bs=0的细胞,以节省存储空间。
  87. ec5his = torch.zeros(bs, self.tracklength, self.ecnum)
  88. ca1his = torch.zeros(bs, self.tracklength, self.ca1num)
  89. else:
  90. ec3his = torch.zeros(self.tracklength, self.ecnum) # 注意,这里只保留bs=0的细胞,以节省存储空间。
  91. ec5his = torch.zeros(self.tracklength, self.ecnum)
  92. ca1his = torch.zeros(self.tracklength, self.ca1num)
  93. actlist = torch.zeros(bs, self.tracklength, self.actnum) # 是float取值而不是01值
  94. for x in range(self.tracklength):
  95. ca3 = self.getCA3output(x)
  96. # # ca1 tuft部分必须限制大小,否则可能导致最终结果过大; Basal部分的输入是0~1之间,Tuft部分的增益是1~2之间
  97. # ca1 = torch.relu(
  98. # torch.matmul(ca3, self.wca3ca1)
  99. # * (1 + torch.sigmoid(torch.matmul(ec3, self.wec3ca1)))
  100. # - self.ca1bias)
  101. ca1 = torch.clip(
  102. torch.matmul(ca3, self.wca3ca1)
  103. * (1 + torch.sigmoid(torch.matmul(ec3, self.wec3ca1)))
  104. - self.ca1bias, 0, 1)
  105. # 注意这里取消了EC5的Bias,如果需要就只能依靠CA1产生,对训练结果没有负面影响
  106. ec5 = ec5 + 10 * self.ts * torch.matmul(ca1, self.wca1ec5)
  107. # 不同的EC5发放率截断(递归迭代)方法,导致EC5范围不同,进而导致EC3持续时间不同。
  108. # 注意,根据Magee的结论应该EC5均值应取exp(-ts/tau)=0.96
  109. ec5 = 0.69 + 0.3 * torch.sigmoid(4 * (ec5 - 0.3)) # 与y=x的交点为0.97,最大值0.99
  110. # # 最经典的做法,没有输入的话就保持不变,有输入则按照0.6的比例上拉到1
  111. # ec3 = ec5 * ec3
  112. # cue = (ec3input[:, x, :] > 0)
  113. # ec3[cue] = (1 - 0.6) * ec3[cue] + 0.6 * 1 # 希望刻画的是,将state=0的cue EC3,以0.6的概率转化为state=1
  114. # 输入为,sensory*(上拉后的值-ec3)
  115. ec3 = ec5 * ec3 + 0.6 * (1 - ec3) * ec3input[:, x, :]
  116. # 加入EC3的随机切变
  117. is_ec3_noised = (torch.rand(bs, self.ecnum) < 0.04 * self.ts) # 本轮中每个EC3细胞是否添加noise
  118. ec3[is_ec3_noised] = 0.5 * ec3[is_ec3_noised] + 0.5 * 0.6 # 用以保证noised之后的EC3发放率在0.6以下
  119. # ec3 = torch.clip(ec3, 0, 1) # 其实不需要这个,机制上已经保证了EC3的发放率在01之间。
  120. actCell = torch.matmul(ca1, self.wca1act) + self.actbias
  121. actlist[:, x, :] = actCell
  122. if isSaveAll:
  123. ec3his[:, x, :] = ec3[:, :] # 只取第一个细胞进行记录
  124. ec5his[:, x, :] = ec5[:, :]
  125. ca1his[:, x, :] = ca1[:, :]
  126. else:
  127. ec3his[x, :] = ec3[0, :] # 只取第一个细胞进行记录
  128. ec5his[x, :] = ec5[0, :]
  129. ca1his[x, :] = ca1[0, :]
  130. return actlist, ec3his, ec5his, ca1his, ec3, ec5, ca1
  131. def cue_gen_StimuNum(actnum, ecnum=100, cue_ratio=0.2):
  132. """
  133. 根据刺激类型的数量,生成几种刺激编码。用于CS+-任务,CS1234任务和Lap任务
  134. :param cue_ratio: 每个线索激活多少比例的EC3细胞
  135. :param actnum: 总共包含几种刺激
  136. :param ecnum:
  137. :return:
  138. """
  139. cuePattern = torch.zeros(actnum, ecnum)
  140. for cueType in range(actnum):
  141. cuePattern[cueType, :] = (torch.rand(1, ecnum) < cue_ratio) # 每个细胞是否作为本轮被激活的cue细胞。注意有可能有的细胞几个线索都响应
  142. return cuePattern
  143. jiajian_action_area = range(80, 90) # 加减任务的action区域
  144. def pickup_jiajian(last_cueUsed, tracklength):
  145. """
  146. 对于每一个trail,根据线索类型决定每个位置上是否有奖励
  147. 对于CS+、CS-任务而言,只有CS+(cueUsed=0)的时候才需要在一个区间内lick
  148. :param last_cueUsed: (bs)
  149. :param tracklength: 注意,这里使用的tracklength推荐为200,也因此修改了lick_label
  150. :return:
  151. cueUsed: (bs)
  152. """
  153. bs = last_cueUsed.shape[0]
  154. cueUsed = np.random.randint(0, 2, bs)
  155. lick_label = torch.zeros(bs, tracklength)
  156. for i in range(bs):
  157. if cueUsed[i] == 0:
  158. lick_label[i, jiajian_action_area] = 1 # 这里使用固定的位置进行lick,而不是像其他任务一样使用tracklength的某个比例
  159. return cueUsed, lick_label
  160. def pickup_decorrelate(last_cueUsed, tracklength):
  161. """
  162. CS+(cue=0)对应far,CS-(cue=1)对应near。
  163. :param last_cueUsed: (bs)
  164. :param tracklength:
  165. :return:
  166. lick_label: (bs, x)
  167. """
  168. bs = last_cueUsed.shape[0]
  169. cueUsed = np.random.randint(0, 2, bs)
  170. lick_label = torch.zeros(bs, tracklength)
  171. for i in range(bs):
  172. if cueUsed[i] == 0:
  173. lick_label[i, int(0.9 * tracklength):tracklength] = 1
  174. if cueUsed[i] == 1:
  175. lick_label[i, int(0.7 * tracklength):int(0.8 * tracklength)] = 1
  176. return cueUsed, lick_label
  177. def pickup_1234(last_cueUsed, tracklength):
  178. """
  179. 对于每一个trail,根据线索类型决定每个位置上是否有奖励
  180. 对于CS1234任务而言,只有CS1、CS2(cueUsed=0或2)的时候才需要在一个区间内lick
  181. :param last_cueUsed: (bs)
  182. :param tracklength:
  183. :return:
  184. """
  185. bs = last_cueUsed.shape[0]
  186. cueUsed = np.random.randint(0, 4, bs)
  187. lick_label = torch.zeros(bs, tracklength)
  188. for i in range(bs):
  189. if cueUsed[i] == 0 or cueUsed[i] == 1:
  190. lick_label[i, int(0.8 * tracklength):int(0.9 * tracklength)] = 1
  191. return cueUsed, lick_label
  192. def pickup_lap(last_cueUsed, tracklength, cycle=4):
  193. """
  194. cueUsed实际上是此时跑的圈数 % cycle, lap任务和 Alter任务合并在一起了
  195. :param cycle: 周期。如果为4,就是传统的Lap任务;如果为2,就是传统的Alternative任务
  196. :param last_cueUsed: (bs)
  197. :param tracklength:
  198. :return:
  199. """
  200. bs = last_cueUsed.shape[0]
  201. cueUsed = (last_cueUsed + 1) % cycle # 在之前的基础上增加一圈
  202. lick_label = torch.zeros(bs, tracklength)
  203. for i in range(bs):
  204. if cueUsed[i] == 0:
  205. lick_label[i, int(0.8 * tracklength):int(0.9 * tracklength)] = 1
  206. return cueUsed, lick_label
  207. def oneCue_ec3_input_gen(cue, tracklength, cueLocation=0.05):
  208. """
  209. 根据线索类型、(一个)线索位置,生成EC3的输入序列
  210. :param cueLocation: float,cueLocation在track上的位置比例
  211. :param cue: float Tensor(bs, ecnum),相当于cuePattern[cueUsed, :]
  212. :param tracklength:
  213. :return: float Tensor(bs, tracklength, ecnum), 每个时刻、每个位置的每个ec3 Sensory输入
  214. """
  215. bs = cue.shape[0]
  216. ecnum = cue.shape[1]
  217. ec3input = torch.zeros(bs, tracklength, ecnum)
  218. # ec3input[:, int(cueLocation * tracklength), :] = cue # 只在一个点进行cue刺激
  219. temp = list(range(10, 20)) # 在一个区间段内进行刺激,用于p01的描述模型
  220. ec3input[:, temp, :] = cue.unsqueeze(1).repeat(1, len(temp), 1)
  221. return ec3input
  222. def evidence_cue_input_gen(bs, ecnum, cuePattern, tracklength, stimu_num=evidence_stimu_num, stimu_duration=evidence_stimu_duration):
  223. """
  224. (2*duration, 3*duration), (4*duration, 5*duration),,,,之间为刺激的位置。
  225. 要注意,设置的刺激位置应该在决策位置之前。
  226. :param bs:
  227. :param ecnum:
  228. :param cuePattern: (2, ecnum)
  229. :param tracklength:
  230. :param stimu_num:总共给予多少个刺激
  231. :param stimu_duration: 每次刺激持续多少个时间步,参数去evidence_settings.py文件中读取
  232. :return:
  233. islick: (bs), int=0 or 1, 跟cueUsed作用差不多
  234. cue_left_right: (bs, stimu_num), int, 0, -1, 1
  235. ec3input: (bs, x, ecnum), tensor
  236. lick_label: (bs, x), tensor float
  237. """
  238. cue_left_right = np.zeros((bs, stimu_num)) # 每个位置是否在左侧有线索
  239. lick_label = torch.zeros(bs, tracklength)
  240. cueLocation = (1 + np.array(range(stimu_num))) * stimu_duration * 2 # 每次刺激的起点位置,(stimu_num)
  241. ec3input = np.zeros((bs, tracklength, ecnum))
  242. islick = [0] * bs
  243. for i in range(bs):
  244. for j in range(stimu_num):
  245. cue_left_right[i, j] = np.random.randint(-1, 1+1) # -1, 0, 1
  246. # 如果是0的话,不给予EC3刺激
  247. if cue_left_right[i, j] == 1:
  248. ec3input[i, cueLocation[j] + range(stimu_duration), :] = np.tile(cuePattern[1
  249. , :], (stimu_duration, 1))
  250. elif cue_left_right[i, j] == -1:
  251. ec3input[i, cueLocation[j] + range(stimu_duration), :] = np.tile(cuePattern[0
  252. , :], (stimu_duration, 1))
  253. if sum(cue_left_right[i, :]) > 0: # 1比-1更多则lick
  254. islick[i] = 1
  255. lick_label[i, int(0.8 * tracklength):int(0.9 * tracklength)] = 1
  256. return islick, cue_left_right, torch.Tensor(ec3input), lick_label
  257. def evidence_poisson(bs, ecnum, cuePattern, tracklength, stimu_num=evidence_stimu_num, stimu_duration=evidence_stimu_duration):
  258. """
  259. 以泊松的方式生成线索位置
  260. :param bs:
  261. :param ecnum:
  262. :param cuePattern: (2, ecnum)
  263. :param tracklength:
  264. :param stimu_num:总共给予多少个刺激
  265. :param stimu_duration: 每次刺激持续多少个时间步,参数去evidence_settings.py文件中读取
  266. :return:
  267. islick: (bs), int=0 or 1, 跟cueUsed作用差不多
  268. cue_left_right: (bs, stimu_num), int, 0, -1, 1
  269. ec3input: (bs, x, ecnum), tensor
  270. lick_label: (bs, x), tensor float
  271. """
  272. cue_left_right = np.zeros((bs, tracklength)) # 0,-1, 1
  273. lick_label = torch.zeros(bs, tracklength)
  274. ec3input = np.zeros((bs, tracklength, ecnum))
  275. islick = [0] * bs
  276. for i in range(bs):
  277. for x in range(int(0.1*tracklength), int(0.7*tracklength)):
  278. cue_left_right[i, x] = np.random.randint(0, 21) # 0~14
  279. if cue_left_right[i, x] == 20:
  280. cue_left_right[i, x] = 1
  281. ec3input[i, x + np.array(range(stimu_duration)), :] += np.tile(cuePattern[1
  282. , :], (stimu_duration, 1))
  283. elif cue_left_right[i, x] == 19:
  284. cue_left_right[i, x] = -1
  285. ec3input[i, x + np.array(range(stimu_duration)), :] += np.tile(cuePattern[0
  286. , :], (stimu_duration, 1))
  287. else: # 如果是0的话,不给予EC3刺激
  288. cue_left_right[i, x] = 0
  289. if sum(cue_left_right[i, :]) > 0: # 1比-1更多则lick
  290. islick[i] = 1
  291. lick_label[i, int(0.8 * tracklength):int(0.9 * tracklength)] = 1
  292. return islick, cue_left_right, torch.Tensor(ec3input), lick_label
  293. def sequence_gen(bs, ecnum, cuePattern, tracklength, stimunum=3, actnum=2):
  294. """
  295. :param bs:
  296. :param ecnum:
  297. :param cuePattern:
  298. :param tracklength:
  299. :param stimunum: 每个trail给予几次气味刺激,原文实验中是5
  300. :param actnum: 有几种行动结果(应该就是2)
  301. :return:
  302. """
  303. odornum = cuePattern.shape[0] # 总共有多少种气味类型
  304. ordernum = 2 # 一次trail给予两次先后刺激
  305. cuelocation = (tracklength * torch.hstack(
  306. ((1 + torch.Tensor(range(stimunum))) * 0.1, torch.Tensor([0.6, 0.7])))).int()
  307. cue = torch.zeros(bs, stimunum + actnum, ecnum) # 准备给予模型的线索刺激,包括记忆阶段的stimunum个和分辨阶段的actnum个
  308. cueUsed = torch.zeros(bs)
  309. for sample in range(bs):
  310. cue_candidate = list(range(odornum))
  311. random.shuffle(cue_candidate)
  312. cue_candidate = cue_candidate[0:stimunum] # 只取前stimunum个气味(的index)
  313. odorA_order = random.randint(0, stimunum - 1)
  314. while True: # 让AB两个气味必须不相同,这样才能进行先后的比较
  315. odorB_order = random.randint(0, stimunum - 1)
  316. if odorB_order != odorA_order:
  317. break
  318. odorA_index = cue_candidate[odorA_order] # Comp处的两个气味选择,注意是原20个气味中的index
  319. odorB_index = cue_candidate[odorB_order]
  320. for stim in range(stimunum):
  321. cue[sample, stim, :] = cuePattern[cue_candidate[stim], :]
  322. cue[sample, stimunum, :] = cuePattern[odorA_index, :]
  323. cue[sample, stimunum + 1, :] = cuePattern[odorB_index, :]
  324. cueUsed[sample] = (odorA_order > odorB_order) + 0.0
  325. num_ith_cue = 0
  326. bs = cue.shape[0]
  327. ecnum = cue.shape[2]
  328. ec3input = torch.zeros(bs, tracklength, ecnum)
  329. for x in range(tracklength):
  330. if num_ith_cue < stimunum + actnum and x == cuelocation[num_ith_cue]:
  331. ec3input[:, x:x + 8, :] = cue[:, num_ith_cue, :].unsqueeze(1) # 每次刺激持续0.7秒
  332. num_ith_cue += 1
  333. lick_label = torch.zeros(bs, tracklength)
  334. for i in range(bs):
  335. if cueUsed[i] == 0:
  336. lick_label[i, int(0.8 * tracklength):int(0.9 * tracklength)] = 1
  337. return cueUsed, ec3input, lick_label
  338. def envb_gen(bs, ecnum, cuePattern, tracklength):
  339. """
  340. 每个轨道上的随机位置进行一次刺激,随后两秒后需要lick
  341. """
  342. cueUsed = np.random.randint(0, 10, bs) # 这个值*5 = 在哪里给予刺激, 总共12种线索类型
  343. cueLocation = cueUsed * 5 + 10
  344. ec3input = np.zeros((bs, tracklength, ecnum))
  345. lick_label = torch.zeros(bs, tracklength)
  346. for sample in range(bs):
  347. ec3input[sample, cueLocation[sample]:cueLocation[sample]+10, :] = np.tile(cuePattern[0, :], (10, 1))
  348. lick_label[sample, cueLocation[sample]+20:cueLocation[sample]+30] = 1
  349. return cueUsed, torch.Tensor(ec3input), lick_label
  350. def doublex(bs, ecnum, cuePattern, tracklength):
  351. """
  352. 在 x0处给予刺激,要求 2*x0处进行lick
  353. """
  354. cueUsed = np.random.randint(0, 9, bs)
  355. cueLocation = (cueUsed+1) * 5
  356. ec3input = np.zeros((bs, tracklength, ecnum))
  357. lick_label = torch.zeros(bs, tracklength)
  358. for sample in range(bs):
  359. ec3input[sample, cueLocation[sample]:cueLocation[sample] + 10, :] = np.tile(cuePattern[0, :], (10, 1))
  360. lick_label[sample, 2*cueLocation[sample]:2*cueLocation[sample] + 10] = 1
  361. return cueUsed, torch.Tensor(ec3input), lick_label
  362. def get_cueUsed_label_by_task(task, last_cueUsed, tracklength):
  363. """
  364. :param task:
  365. :param last_cueUsed: 上一次使用的cueUsed
  366. :param tracklength:
  367. :return:
  368. """
  369. if task == 'jiajian':
  370. cueUsed, lickLabel = pickup_jiajian(last_cueUsed, tracklength) # CS+-的任务
  371. elif task == 'decorrelate':
  372. cueUsed, lickLabel = pickup_decorrelate(last_cueUsed, tracklength) # decorrelate的任务
  373. elif task == 'lap':
  374. cueUsed, lickLabel = pickup_lap(last_cueUsed, tracklength, cycle=4) # decorrelate的任务
  375. elif task == 'alter':
  376. cueUsed, lickLabel = pickup_lap(last_cueUsed, tracklength, cycle=2) # decorrelate的任务
  377. elif task == '1234':
  378. cueUsed, lickLabel = pickup_1234(last_cueUsed, tracklength)
  379. else:
  380. cueUsed, lickLabel = None, None
  381. warnings.warn('Unknown task!')
  382. return cueUsed, lickLabel
  383. def get_anything_by_task(task, bs, ecnum, cuePattern, last_cueUsed, tracklength):
  384. """
  385. 直接获得每个线索、输入、舔的label。
  386. 如果是Evidence任务,还有一个额外的cue_left_right
  387. bs: int
  388. ecnum: int
  389. last_cueUsed: (bs,), int
  390. tracklength: int
  391. :returns:
  392. focus_zone: 每个任务应该关注结果的轨道位置,list 80:90
  393. lick_label: (bs, x)
  394. """
  395. focus_zone = list(range(int(tracklength*0.8), int(tracklength*0.9))) # 除了decorrelate任务以外,其他的任务基本都是这个
  396. if task == 'evidence':
  397. cueUsed, cue_left_right, ec3input, lick_label = evidence_cue_input_gen(bs, ecnum, cuePattern,
  398. tracklength) # cueUsed是01,是否应该舔
  399. elif task == 'evidence_poisson':
  400. cueUsed, cue_left_right, ec3input, lick_label = evidence_poisson(bs, ecnum, cuePattern, tracklength)
  401. elif task == 'sequence':
  402. cueUsed, ec3input, lick_label = sequence_gen(bs, ecnum, cuePattern, tracklength)
  403. cue_left_right = None
  404. focus_zone = list(range(int(tracklength * 0.8), int(tracklength * 0.9)))
  405. elif task == 'envb':
  406. cueUsed, ec3input, lick_label = envb_gen(bs, ecnum, cuePattern, tracklength)
  407. cue_left_right = None
  408. focus_zone = list(range(tracklength)) # 对于envb任务,哪里都有可能需要lick
  409. elif task == 'doublex':
  410. cueUsed, ec3input, lick_label = doublex(bs, ecnum, cuePattern, tracklength)
  411. cue_left_right = None
  412. focus_zone = list(range(tracklength)) # 对于envb任务,哪里都有可能需要lick
  413. else:
  414. cue_left_right = None # 实际上就是什么都没有,只是在保存的时候用于占位
  415. cueUsed, lick_label = get_cueUsed_label_by_task(task, last_cueUsed, tracklength)
  416. if task == 'jiajian':
  417. focus_zone = list(jiajian_action_area) # 因为加减任务的轨道长度是200,因此不能用默认的参数
  418. if task == 'lap' or task == 'alter':
  419. cue = torch.Tensor(np.tile(cuePattern[0, :], [bs, 1]))
  420. else:
  421. cue = cuePattern[cueUsed, :] # 注意,这个操作之后似乎cue变量就变成了0和1的矩阵,需要用*.bool()还原回布尔变量
  422. ec3input = oneCue_ec3_input_gen(cue, tracklength)
  423. if task == 'lap' or task == 'alter':
  424. ec3input[cueUsed == 0, 90:100, :] = cuePattern[1, :] # 在奖励之处给一个额外的刺激
  425. if task == 'decorrelate':
  426. focus_zone = list(range(int(tracklength * 0.7), int(tracklength * 0.8))) + list(range(int(tracklength * 0.9), int(tracklength * 1.0)))
  427. return cueUsed, ec3input, lick_label, cue_left_right, focus_zone
  428. def eval_prepare(task, cueNum, bs, ec3_last, ec5_last, ca1_last, cueUsed, eval_bs=1000, loopnum=0):
  429. """
  430. 在eval之前,对于数据的预处理。主要是将各类细胞的last数据处理好。
  431. eval_bs = 1000 # 用于eval的样本数量,越大越好
  432. loopnum: 如果是1,则是用于cs代码的eval设置;如果大于1,则是dv代码的eval设置
  433. """
  434. if task == 'lap' or task == 'alter': # 单独准备Lap任务的初始值,因为每轮和每轮之间的cueUsed必须是连续的
  435. repeat_counts = 4 if task == 'lap' else 2
  436. first_index = [-1] * repeat_counts # 搜索四个lap情况作为eval的细胞初值
  437. for i in range(repeat_counts):
  438. for index in range(bs):
  439. if cueUsed[index] == i:
  440. first_index[i] = index
  441. break
  442. assert all(x >= 0 for x in first_index)
  443. temp = int(eval_bs / repeat_counts) # 复制每一行的次数
  444. if loopnum>=1:
  445. for loop in range(loopnum): # 复制first_index的每一行并堆叠成(eval_bs, cellNum)的形式
  446. ec3_last[loop] = torch.vstack([ec3_last[loop][first_index[i], :].repeat(temp, 1) for i in range(repeat_counts)])
  447. ec5_last[loop] = torch.vstack([ec5_last[loop][first_index[i], :].repeat(temp, 1) for i in range(repeat_counts)])
  448. ca1_last[loop] = torch.vstack([ca1_last[loop][first_index[i], :].repeat(temp, 1) for i in range(repeat_counts)])
  449. else:
  450. ec3_last = torch.vstack([ec3_last[first_index[i], :].repeat(temp, 1) for i in range(repeat_counts)])
  451. ec5_last = torch.vstack([ec5_last[first_index[i], :].repeat(temp, 1) for i in range(repeat_counts)])
  452. ca1_last = torch.vstack([ca1_last[first_index[i], :].repeat(temp, 1) for i in range(repeat_counts)])
  453. last_cueUsed = np.repeat(np.array(range(repeat_counts)), repeats=temp)
  454. else:
  455. last_cueUsed = np.random.randint(0, cueNum, eval_bs)
  456. if loopnum>=1:
  457. for loop in range(loopnum):
  458. ec3_last[loop] = ec3_last[loop][0, :].repeat(eval_bs, 1) # 以第一个元素的各个细胞的值,作为eval的初值
  459. ec5_last[loop] = ec5_last[loop][0, :].repeat(eval_bs, 1)
  460. ca1_last[loop] = ca1_last[loop][0, :].repeat(eval_bs, 1)
  461. else:
  462. ec3_last = ec3_last[0, :].repeat(eval_bs, 1) # 以第一个元素的各个细胞的值,作为eval的初值
  463. ec5_last = ec5_last[0, :].repeat(eval_bs, 1)
  464. ca1_last = ca1_last[0, :].repeat(eval_bs, 1)
  465. return last_cueUsed, ec3_last, ec5_last, ca1_last
  466. def get_cue_num(task):
  467. if task == 'lap' or task == '1234':
  468. cueNum = 4
  469. elif task == 'sequence':
  470. cueNum = 3
  471. elif task == 'envb':
  472. cueNum = 12 # 只是一小部分的线索,实际上有60个种类
  473. elif task == 'doublex':
  474. cueNum = 8 # 只是一小部分的线索,实际上有60个种类
  475. else:
  476. cueNum = 2
  477. return cueNum
  478. def net_train(task, epochNum=500, bs=30, lr=0.003, given_net=None, given_cuePattern=None, isShuffleCA3=False,
  479. pre_losshis=None):
  480. """
  481. :param task: jiajian, decorrelate, 1234, lap
  482. :param epochNum:
  483. :param bs:
  484. :param lr:
  485. :param given_net: 已经训练好的模型,如果有的话(可以从hpc_rnn.pth中加载)
  486. :param given_cuePattern:
  487. :param isShuffleCA3: 是否重新排布的CA3的序列,用于进行环境remap泛化实验
  488. :param pre_losshis: 过去模型的loss表现,如果有的话可以用来放在loss曲线图中进行比较
  489. :return:
  490. """
  491. start_time = time.time() # 单位;秒
  492. # 进行网络训练
  493. tracklength = 100
  494. ca1num = 100
  495. ecnum = 100
  496. actnum = 2
  497. if given_net is None:
  498. net = HPCrnn(ca1num=ca1num, ecnum=ecnum, tracklength=tracklength, actnum=actnum)
  499. else:
  500. net = given_net
  501. net.init_wca1act()
  502. if isShuffleCA3:
  503. net.shuffleCA3()
  504. # criterion = nn.CrossEntropyLoss() # 普通的二分类
  505. criterion = nn.CrossEntropyLoss(weight=torch.Tensor([1, 10])) # 对于有奖励但没舔到时有非常大的惩罚,舔而没有奖励时则惩罚较小
  506. # 从结果上看,施加权重的loss训练效果更好,且lick行为符合生物的演变过程
  507. optimizer = torch.optim.Adam(net.parameters(), lr=lr)
  508. '''初始化cue相关'''
  509. if task == 'lap' or task == '1234':
  510. cueNum = 4
  511. else:
  512. cueNum = 2 # jiajian, decorrelate, alter
  513. cueUsed = np.random.randint(0, cueNum, bs) # 初始化一下,用于传递给之后的pickup函数
  514. if given_cuePattern is None:
  515. cuePattern = cue_gen_StimuNum(cueNum, ecnum)
  516. else:
  517. cuePattern = given_cuePattern
  518. cueUsedhis = np.zeros([epochNum, bs])
  519. ca1_all_his = torch.zeros(epochNum, tracklength, ca1num)
  520. ec5_all_his = torch.zeros(epochNum, tracklength, ecnum)
  521. ec3_all_his = torch.zeros(epochNum, tracklength, ecnum)
  522. ec3_last = torch.zeros(bs, ecnum)
  523. ec5_last = torch.rand(bs, ecnum)
  524. ca1_last = torch.zeros(bs, ca1num)
  525. losshis = torch.zeros(epochNum)
  526. actionhis = torch.zeros(epochNum, bs, tracklength) # 用于绘制lick历史
  527. '''正式进行epoch迭代'''
  528. real_epochNum = epochNum
  529. loss = torch.Tensor([10000])
  530. for epoch in range(epochNum):
  531. # 如果loss已经很小了,就直接终止训练
  532. if loss.item() < 0.001:
  533. real_epochNum = epoch
  534. print('End Training.')
  535. break
  536. if task == 'evidence':
  537. cueUsed, cue_left_right, ec3input, lick_label = evidence_cue_input_gen(bs, ecnum, cuePattern, tracklength)
  538. elif task == 'evidence_poisson':
  539. cueUsed, cue_left_right, ec3input, lick_label = evidence_poisson(bs, ecnum, cuePattern, tracklength)
  540. else:
  541. cueUsed, lick_label = get_cueUsed_label_by_task(task, cueUsed, tracklength)
  542. if task == 'lap' or task == 'alter':
  543. cue = torch.Tensor(np.tile(cuePattern[0, :], [bs, 1]))
  544. else:
  545. cue = cuePattern[cueUsed, :] # 注意,这个操作之后似乎cue变量就变成了0和1的矩阵,需要用*.bool()还原回布尔变量
  546. ec3input = oneCue_ec3_input_gen(cue, tracklength)
  547. cueUsedhis[epoch, :] = cueUsed
  548. optimizer.zero_grad()
  549. pred, ec3_this_his, ec5_this_his, ca1_this_his, ec3_last1, ec5_last1, ca1_last1 = net(ec3input, ec3_last,
  550. ec5_last,
  551. ca1_last)
  552. isLicked = torch.argmax(pred, 2) == 1 # (bs, tracklength)
  553. actionhis[epoch, :, :] = isLicked
  554. # 对actlist 和 licklabel进行展开以进行loss计算
  555. pred = pred.reshape(bs * tracklength, actnum)
  556. lick_label = lick_label.reshape(bs * tracklength)
  557. loss = criterion(pred, lick_label.long())
  558. loss.backward()
  559. # nn.utils.clip_grad_norm_(net.parameters(), max_norm=20, norm_type=2) # 梯度截断
  560. optimizer.step()
  561. ca1_all_his[epoch, :, :] = ca1_this_his # epoch, x, i
  562. ec5_all_his[epoch, :, :] = ec5_this_his
  563. ec3_all_his[epoch, :, :] = ec3_this_his
  564. ec3_last = ec3_last1.detach() # 虽然不知道为什么,但是这样就没有bug,用clone()的方法会有bug
  565. ec5_last = ec5_last1.detach()
  566. ca1_last = ca1_last1.detach()
  567. print('%d, %.5f' % (epoch, loss.item()))
  568. losshis[epoch] = loss
  569. duration_time = time.time() - start_time
  570. print('总训练时间:%.2f' % duration_time)
  571. if given_net is None: # 只有在新训练模型的时候才保存模型
  572. torch.save({'task': task, 'cuePattern': cuePattern, 'net': net, 'losshis': losshis.data.numpy()}, 'hpc_rnn.pth')
  573. np.savez('cells.npz', ca1_all_his.data.numpy(), ec5_all_his.data.numpy(), ec3_all_his.data.numpy(), cueUsedhis,
  574. actionhis)
  575. plt.plot(losshis.data.numpy())
  576. if pre_losshis is not None: # 加上以前的losshis的曲线(黑色),用于比较loss下降速度
  577. plt.plot(pre_losshis, color='black')
  578. plt.title('batch size: %d, lr: %.4f' % (bs, lr))
  579. plt.savefig('./fig_result/_loss result.jpg')
  580. plt.show()
  581. # 对模型进行测试,获得任务准确率,并将整个batch的结果保存
  582. net.eval()
  583. eval_bs = 1000
  584. last_cueUsed, ec3_last, ec5_last, ca1_last = \
  585. eval_prepare(task, cueNum, bs, ec3_last, ec5_last, ca1_last, cueUsed, eval_bs=eval_bs)
  586. cueUsed_eval, ec3input_eval, lick_label_eval, cue_left_right, focus_zone = \
  587. get_anything_by_task(task, eval_bs, ecnum, cuePattern, last_cueUsed, tracklength) # 直接获取输入数据
  588. pred, ec3_last_his, ec5_last_his, ca1_last_his, _, _, _ = net(ec3input_eval, ec3_last, ec5_last, ca1_last,
  589. isSaveAll=True)
  590. pred = pred[:, focus_zone, :].reshape(eval_bs * len(focus_zone), actnum) # 只关注focus_zone区域部分的准确率
  591. label_test = lick_label_eval[:, focus_zone].reshape(eval_bs * len(focus_zone))
  592. acc = torch.mean(((torch.argmax(pred, 1).reshape(eval_bs * len(focus_zone)) == label_test) + 0).float())
  593. print('accuracy: %.5f' % acc.float())
  594. np.savez('eval_result.npz', ca1_last_his.data.numpy(), ec5_last_his.data.numpy(), ec3_last_his.data.numpy(),
  595. cueUsed_eval, cue_left_right)
  596. print('evaluation done.')
  597. if __name__ == '__main__':
  598. mode = 'training' # 本次运行,是训练还是观察结果
  599. # mode = 'viewing'
  600. # mode = 'generalizing' # 必须先train然后才能测试泛化
  601. # task = 'jiajian' # 任务类型
  602. # task = 'decorrelate'
  603. # task = 'lap'
  604. # task = 'alter'
  605. # task = '1234'
  606. task = 'evidence' # 目前没法学习3个以上的刺激,但DV代码可以
  607. epochNum = 500
  608. batch_size = 30
  609. lr = 0.003
  610. if task == 'lap' or task == '1234':
  611. cueNum = 4
  612. else:
  613. cueNum = 2
  614. seed = 6
  615. torch.manual_seed(seed)
  616. random.seed(seed)
  617. np.random.seed(seed)
  618. # ——————————训练网络并保存网络结构、中间运行过程
  619. if mode == 'training':
  620. net_train(task, epochNum, batch_size, lr)
  621. # ——————————读取网络并测试和查看权重
  622. if mode == 'viewing':
  623. D = np.load('cells.npz')
  624. ca1his, ec5his, ec3his, cueUsedhis, actionhis = D['arr_0'], D['arr_1'], D['arr_2'], D['arr_3'], D['arr_4']
  625. train_his = ca1his # 只选择一类细胞进行绘制
  626. # 获取eval的数据并进行accuracy分析, (bs, tracklength, ca1num)
  627. Deval = np.load('eval_result.npz')
  628. ca1_last_his, ec5_last_his, ec3_last_his, cueUsed_eval = Deval['arr_0'], Deval['arr_1'], Deval['arr_2'], Deval[
  629. 'arr_3']
  630. eval_his = ca1_last_his
  631. myplot.viewing(task, cueNum, train_his, actionhis, cueUsedhis, eval_his, cueUsed_eval)
  632. # ——————————加载模型,打乱CA3并重新训练
  633. if mode == 'generalizing':
  634. temp = torch.load('hpc_rnn.pth')
  635. net = temp['net']
  636. losshis = temp['losshis']
  637. cuePattern = temp['cuePattern']
  638. assert (temp['task'] == task)
  639. '''不改变Sensory输入,但对于CA3位置进行remap的泛化检验'''
  640. # net_train(task, epochNum, batch_size, lr, given_net=net, given_cuePattern=cuePattern, isShuffleCA3=True,
  641. # pre_losshis=losshis)
  642. '''改变Sensory输入,但CA3的位置不变进行remap的泛化检验'''
  643. net_train(task, epochNum, batch_size, lr, given_net=net, pre_losshis=losshis)
  644. print('end')

cs.py at commit 4c5bb7c, no license · at the source

Overview

Authors: Yuechen Liu1, Zishun Wang1, Chen Qiao1, Zongben Xu1
ORCID iDs: Chen Qiao
  1. School of Mathematics and Statistics, Xi’an Jiaotong University, Xi’an, China
Institutions: Xi'an Jiaotong University (China)
Journal: PLoS computational biology, volume 22, issue 6, article e1014438
Dates: received 25 February 2025; accepted 14 June 2026; published online 29 June 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1371/journal.pcbi.1014438 · PMID 42371951 · PMCID PMC13336475 · OpenAlex W4406778998
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: cognitive (subfield)
Methods: Statistics, Machine learning
MeSH: Hippocampus*, Learning*, Memory, Short-Term*, Models, Neurological*, Animals, Computational Biology (* major topic)
Topic: Memory and Neural Mechanisms (Cognitive Neuroscience, Neuroscience), according to OpenAlex
Funding: National Natural Science Foundation of China (Nos. 12271429, 12226007, 12090021)
Citations: not cited yet (Europe PMC); 50 references in the paper

Abstract

Hippocampal formation (HF) supports both the temporary maintenance of task-relevant information and rapid relearning when task structure is preserved. Here we ask what circuit mechanism can link these two functions within a single framework. We propose a model named Generalization and Associative Temporary Encoding (GATE), whose core idea is a self-gating re-entrant EC3–CA1–EC5–EC3 loop. In each lamella, EC3 provides a memory substrate, CA1 selectively reads out the retained information under CA3 gating, and EC5 feeds back to regulate the next EC3 state. Repeating this loop across dorsoventral lamellae yields representational scales that range from local cue-dependent coding to a broader task-related structure. In simple tasks, the single-lamellar model captures selective maintenance and produces place- and splitter-like CA1 activity. In more complex tasks, the multi-lamellar model develops lap, evidence, trace, and other task-relevant representations. Under structure-preserving changes in sensory coding, positional scaffold, or task parameters, the model reuses learned representations and relearns faster. GATE provides a hypothesis-generating computational framework for studying how hippocampal-like circuit motifs may support selective memory gating and structure-preserving relearning.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repository

Its files are read in the Code ↔ Paper reader above, with 1 match between paragraphs and lines of code.

gate-world/gate

License: none: the authors keep all their rights
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: 4c5bb7c7d0ba1d913ba0dd5869f560d3a6bf0f8c, 22 January 2025
Languages: Python (47), MATLAB (2)
Size: 51 files, 49 scripts
Software Heritage: not archived
Found in: “Data Availability”
Holds: README
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (34 files), Matplotlib (31 files), PyTorch (24 files), SciPy (7 files), scikit-learn (2 files), seaborn (2 files), pandas (1 file), UMAP (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
50 files

The paper's code and data availability statement is in the Data section.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 49 scripts, each with its path and the digest of its content;
  • 1 match between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data Availability

All simulations and training are run via custom code in Python 3.10.11 / Pytorch 2.0.1. The code is available at https://github.com/gate-world/gate.

Reproduced under the paper's license (CC BY), from the paper cited above.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 2, 28 September 2026

  • Funding: added National Natural Science Foundation of China: Nos. 12271429, 12226007, 12090021

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 4 authors, 6 MeSH terms, 47 references.

Cite

This paper

Liu, Y., Wang, Z., Qiao, C., & Xu, Z. (2026). GATE: Adaptive learning with working memory by information gating in multi-lamellar hippocampal formation. PLoS computational biology, 22(6), e1014438. https://doi.org/10.1371/journal.pcbi.1014438

BibTeX

@article{liu2026gate,
author = {Liu, Yuechen and Wang, Zishun and Qiao, Chen and Xu, Zongben},
title = {{GATE: Adaptive learning with working memory by information gating in multi-lamellar hippocampal formation}},
journal = {PLoS computational biology},
year = {2026},
month = jun,
volume = {22},
number = {6},
pages = {e1014438},
publisher = {PLOS},
issn = {1553-734X},
doi = {10.1371/journal.pcbi.1014438},
url = {https://doi.org/10.1371/journal.pcbi.1014438},
pmid = {42371951},
pmcid = {PMC13336475}
}

RIS

TY - JOUR
AU - Liu, Yuechen
AU - Wang, Zishun
AU - Qiao, Chen
AU - Xu, Zongben
TI - GATE: Adaptive learning with working memory by information gating in multi-lamellar hippocampal formation
T2 - PLoS computational biology
J2 - PLoS Comput Biol
PY - 2026
DA - 2026/06/29
VL - 22
IS - 6
SP - e1014438
SN - 1553-734X
PB - PLOS
DO - 10.1371/journal.pcbi.1014438
UR - https://doi.org/10.1371/journal.pcbi.1014438
LA - en
ER -

CSL-JSON

{
"id": "10.1371/journal.pcbi.1014438",
"type": "article-journal",
"title": "GATE: Adaptive learning with working memory by information gating in multi-lamellar hippocampal formation",
"container-title": "PLoS computational biology",
"author": [
{
"family": "Liu",
"given": "Yuechen"
},
{
"family": "Wang",
"given": "Zishun"
},
{
"family": "Qiao",
"given": "Chen"
},
{
"family": "Xu",
"given": "Zongben"
}
],
"container-title-short": "PLoS Comput Biol",
"volume": "22",
"issue": "6",
"page": "e1014438",
"DOI": "10.1371/journal.pcbi.1014438",
"PMID": "42371951",
"PMCID": "PMC13336475",
"ISSN": "1553-734X",
"publisher": "PLOS",
"URL": "https://doi.org/10.1371/journal.pcbi.1014438",
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
29
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.7554/elife.106506 [code]
Modeling flexible behavior with remapping-based hippocampal sequence learning.
Journal: eLife
In common: SciPy, Matplotlib, NumPy, cognitive, 6 references
[2] doi:10.1038/s41467-026-74357-6 [code]
Hippocampo-neocortical interaction as compressive retrieval-augmented generation.
Journal: Nature communications
In common: UMAP, PyTorch, seaborn, 5 other tools, 2 references
[3] doi:10.1002/advs.77419 [code]
Early Spatial and Contextual Coding Deficits in Hippocampal CA1 Precede Performance Decline in an Alzheimer's Disease Model.
Journal: Advanced science (Weinheim, Baden-Wurttemberg, Germany)
In common: 6 references
[4] doi:10.1038/s42003-026-10064-8 [code]
The hippocampal CA3 area implements sequence learning of discontinuous episodes.
Journal: Communications biology
In common: 6 references
[5] doi:10.7554/elife.105953 [code]
Top-down feedback in deep neural networks leads to functional differences during audiovisual integration.
Journal: eLife
In common: UMAP, PyTorch, seaborn, 5 other tools, 1 reference
[6] doi:10.1038/s41467-026-77240-6
Prefrontal-thalamic goal states organize spatially aligned hippocampal maps.
Journal: Nature communications
In common: 6 references
[7] doi:10.1038/s41467-026-74358-5 [code]
Brain-inspired spatial intelligence for embodied agents.
Journal: Nature communications
In common: PyTorch, seaborn, scikit-learn, 4 other tools, cognitive, 2 references
[8] doi:10.1038/s42256-026-01254-4 [code]
Neural sampling from cognitive maps enables goal-directed imagination and planning.
Journal: Nature machine intelligence
In common: PyTorch, seaborn, scikit-learn, 2 other tools, cognitive, 3 references
[9] doi:10.1038/s41467-026-77318-1 [code]
Offline generative network reconfiguration guides insight-like accelerated learning by assimilation into schema in rats.
Journal: Nature communications
In common: seaborn, scikit-learn, pandas, 2 other tools, 3 references
[10] doi:10.1002/hipo.70131 [code]
Decoding Medial Entorhinal Cortical Dynamics Produces Planning-Like Alternations in Hippocampal theta Sequences.
Journal: Hippocampus
In common: scikit-learn, pandas, SciPy, 2 other tools, 3 references

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.