OSCR

Towards a bridge between intracerebral and surface EEG signatures of conscious report.

Code ↔ Paper

2 matches 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 2 matches
  1. [1] § Statistical analyses › Surface EEG analysis › Event-related potentials ↔ Exocos_attention_conscious_report.ipynb, lines 120–149 · score 0.57 · cue onset, target stimulus, accuracy, perception, position, neural
  2. [2] § Materials and Methods › Experimental task ↔ Exocos_attention_conscious_report.ipynb, lines 120–149 · score 0.55 · target stimulus, field, duration, delay, threshold, perceptual

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

Jupyter notebook · 2,183 lines · 76 KB · no license · 2 matches

  1. # %% [markdown]
  2. # <a href="https://colab.research.google.com/github/jianghao-liu/attention-conscious-report/blob/main/Exocos_attention_conscious_report.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>
  3. # %% [markdown]
  4. #
  5. #
  6. # ## "Fronto-parietal networks shape human conscious report through attention gain and reorienting"
  7. #
  8. # Jianghao Liu, Dimitri J. Bayle, Alfredo Spagna, Jacobo D. Sitt, Alexia Bourgeois, Katia Lehongre, Sara Fernandez-Vidal, Claude Adam, Virginie Lambrecq, Vincent Navarro, Tal Seidel Malkinson, Paolo Bartolomeo
  9. #
  10. # https://www.biorxiv.org/content/10.1101/2022.04.10.487690v4
  11. #
  12. #
  13. #
  14. # ## Using RNN to simulate consciousness task
  15. #
  16. # 1. Set environment
  17. # 2. Define a new task model with RNN
  18. # 3. Model training
  19. # 4. Model probing and trial sample
  20. # 5. PCA/t-SNE analysis to investigate task representation
  21. # 6. Trajectory k-mean method about temporal dynamics
  22. # 7. PCA/t-SNE analysis on cluster
  23. # 8. lesion analysis by cluster
  24. # 9. NeuroData PCA visualization
  25. #
  26. # ***
  27. #
  28. # %% [markdown]
  29. # ## 1 - Set environment
  30. # %%
  31. # THIS CELL SETS STUFF UP FOR DEMO / COLLAB. THIS CELL CAN BE IGNORED.
  32. #-------------------------------------GET RID OF TF DEPRECATION WARNINGS---------------------------------------#
  33. import warnings
  34. warnings.filterwarnings('ignore', category=FutureWarning)
  35. import tensorflow as tf
  36. tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
  37. #----------------------------------INSTALL PSYCHRNN IF IN A COLAB NOTEBOOK-------------------------------------#
  38. # Installs the correct branch / release version based on the URL. If no branch is provided, loads from master.
  39. try:
  40. import google.colab
  41. IN_COLAB = True
  42. except:
  43. IN_COLAB = False
  44. if IN_COLAB:
  45. import json
  46. import re
  47. import ipykernel
  48. import requests
  49. from requests.compat import urljoin
  50. import os
  51. from notebook.notebookapp import list_running_servers
  52. kernel_id = re.search('kernel-(.*).json',
  53. ipykernel.connect.get_connection_file()).group(1)
  54. servers = list_running_servers()
  55. for ss in servers:
  56. response = requests.get(urljoin(ss['url'], 'api/sessions'),
  57. params={'token': ss.get('token', '')})
  58. for nn in json.loads(response.text):
  59. if nn['kernel']['id'] == kernel_id:
  60. relative_path = nn['notebook']['path'].split('%2F')
  61. if 'blob' in relative_path:
  62. blob = relative_path[relative_path.index('blob') + 1]
  63. !pip install git+https://github.com/murraylab/PsychRNN@$blob
  64. else:
  65. !pip install git+https://github.com/murraylab/PsychRNN
  66. if not os.path.exists("./weights"):
  67. os.makedirs("./weights")
  68. # %%
  69. !pip install psychrnn
  70. # %%
  71. from google.colab import drive
  72. drive.mount('/content/drive')
  73. # %%
  74. !pip install scipy
  75. from psychrnn.backend.models.basic import Basic
  76. import tensorflow as tf
  77. from matplotlib import pyplot as plt
  78. %matplotlib inline
  79. import scipy.io
  80. import numpy as np
  81. import random
  82. seed=2021
  83. tf.compat.v2.random.set_seed(seed)
  84. random.seed(seed)
  85. np.random.seed(seed)
  86. from sklearn.decomposition import PCA
  87. from sklearn.manifold import TSNE
  88. from scipy import stats
  89. # %% [markdown]
  90. # ## 2 - Define a new task model with RNN
  91. #
  92. #
  93. #
  94. # %%
  95. from psychrnn.tasks.task import Task
  96. import numpy as np
  97. class ExogenousAttention(Task):
  98. """Near-threshold target detection task with exogenous attention effect
  99. Following a fore period, the network receives a cue, followed by a fixed cue-target delay. After the delay the network receives a target stimulus.
  100. Since the position of cue have a impact on the perception of the subsequent target, the network have to report whether the target was present or absent after a second fixed delay.
  101. The network takes two noisy inputs which simulate visual stimuli coming from two sides of the field of view. (:attr:`N_in` = 2).
  102. Two outputs (:attr:`N_out` = 2) with a one hot encoding showing whether the target was present or absent and the side where the target was present (present is 1, absent is 0).
  103. The amplifying effect on stimuli by attention is modelled by multiplying input signal with an attentional gain value, at validly cued position.
  104. Behaviorial performance of the network is measured by the target detection accuracy.
  105. Args:
  106. attention_gain (float, optional): Coefficiant of attentional amplifying effect.
  107. target_indensity (float, optional): Intensity of target stimulus
  108. dt (float): The simulation timestep.
  109. tau (float): The intrinsic time constant of neural state decay.
  110. T (float): The trial length.
  111. N_batch (int): The number of trials per training update.
  112. onset_time (float, optional): Cue onset time in terms of trial length :data:`T`.
  113. stim_duration_1 (float, optional): Cue duration in terms of trial length :data:`T`.
  114. delay_duration_1 (float, optional): Cue-target delay (Stimulus onset asynchrony) in terms of trial length :data:`T`.
  115. stim_duration_2 (float, optional): Target duration in terms of trial length :data:`T`.
  116. delay_duration_2 (float, optional): Delay to prepare the response in terms of trial length :data:`T`.
  117. decision_duration (float, optional): Response duration in terms of trial length :data:`T`.
  118. """
  119. def __init__(self, dt, tau, T, N_batch, attention_gain = 1.5, target_indensity = 0.10, onset_time = None, stim_duration_1 = None, delay_duration_1 = None, stim_duration_2 = None, delay_duration_2 = None, decision_duration = None):
  120. super(ExogenousAttention,self).__init__(2, 2, dt, tau, T, N_batch)
  121. self.attention_gain = attention_gain
  122. self.target_indensity = target_indensity
  123. self.onset_time = onset_time
  124. self.stim_duration_1 = stim_duration_1
  125. self.delay_duration_1 = delay_duration_1
  126. self.stim_duration_2 = stim_duration_2
  127. self.delay_duration_2 = delay_duration_2
  128. self.decision_duration = decision_duration
  129. def generate_trial_params(self, batch, trial):
  130. """"Define parameters for each trial.
  131. Using a combination of randomness, presets, and task attributes, define the necessary trial parameters.
  132. Args:
  133. batch (int): The batch number that this trial is part of.
  134. trial (int): The trial number of the trial within the batch.
  135. Returns:
  136. dict: Dictionary of trial parameters.
  137. :Dictionary Keys: (millisecond)
  138. * **stimulus_1** (*float*) -- Start time for stimulus one. :data:`onset_time`.
  139. * **delay1** (*float*) -- Start time for the delay. :data:`onset_time` + :data:`stimulus_duration_1`.
  140. * **stimulus_2** (*float*) -- Start time in for stimulus one. :data:`onset_time` + :data:`stimulus_duration_1` + :data:`delay_duration_1`.
  141. * **delay2** (*float*) -- Start time for the delay. :data:`onset_time` + :data:`stimulus_duration_1` + :data:`delay_duration_1` + :data:`stimulus_duration_2`.
  142. * **decision** (*float*) -- Start time in for decision period. :data:`onset_time` + :data:`stimulus_duration_1` + :data:`delay_duration_1` + :data:`stimulus_duration_2`+ delay_duration_2.
  143. * **end** (*float*) -- End of decision period. :data:`onset_time` + :data:`stimulus_duration_1` + :data:`delay_duration` + :data:`stimulus_duration_2` + :data:`decision_duration`.
  144. * **stim_noise** (*float*) -- Scales the stimlus noise. following Gaussian N(0,0.05) for visual processing noise
  145. * **cue_position** (*float*) -- Indicates whether the cue is present in left '0' or right side '1'.
  146. * **target_position** (*float*) -- Indicates whether the target is present in left '0' or right side '1'.
  147. * **detection** (*float*) -- Indicates whether the target is present in this trial : '0' absent or '1' present.
  148. """
  149. # ----------------------------------
  150. # Define parameters of a trial
  151. # ----------------------------------
  152. params = dict()
  153. if self.onset_time is None:
  154. onset_time = 200
  155. else:
  156. onset_time = self.onset_time
  157. if self.stim_duration_1 is None:
  158. stim_duration_1 = 160
  159. else:
  160. stim_duration_1 = self.stim_duration_1
  161. if self.delay_duration_1 is None:
  162. delay_duration_1 = 200
  163. else:
  164. delay_duration_1 = self.delay_duration_1
  165. if self.stim_duration_2 is None:
  166. stim_duration_2 = 160
  167. else:
  168. stim_duration_2 = self.stim_duration_2
  169. if self.delay_duration_2 is None:
  170. delay_duration_2 = 200
  171. else:
  172. delay_duration_2 = self.delay_duration_2
  173. if self.decision_duration is None:
  174. decision_duration = 100
  175. else:
  176. decision_duration = self.decision_duration
  177. params['stimulus_1'] = onset_time
  178. params['delay_1'] = onset_time + stim_duration_1
  179. params['stimulus_2'] = onset_time + stim_duration_1 + delay_duration_1
  180. params['delay_2'] = onset_time + stim_duration_1 + delay_duration_1 + stim_duration_2
  181. params['decision'] = onset_time + stim_duration_1 + delay_duration_1 + stim_duration_2 + delay_duration_2
  182. params['end'] = onset_time + stim_duration_1 + delay_duration_1 + stim_duration_2 + delay_duration_2 + decision_duration
  183. params['cue_position'] = np.random.choice([0, 1])
  184. params['target_position'] = np.random.choice([0, 1])
  185. params['detection'] = np.random.choice([0,1], p = [0.33,0.67])
  186. params['stim_noise'] = 0.1
  187. params['attention_gain'] = self.attention_gain
  188. params['target_indensity'] = self.target_indensity
  189. return params
  190. def trial_function(self, time, params):
  191. """ Compute the trial properties at the given time.
  192. Based on the params compute the trial stimulus (x_t), correct output (y_t), and mask (mask_t) at the given time.
  193. Args:
  194. time (int): The time within the trial (0 <= time < T).
  195. params (dict): The trial params produced generate_trial_params()
  196. Returns:
  197. tuple:
  198. x_t (ndarray(dtype=float, shape=(N_in,))): Trial input at time given params.
  199. y_t (ndarray(dtype=float, shape=(N_out,))): Correct trial output at time given params.
  200. mask_t (ndarray(dtype=bool, shape=(N_out,))): True if the network should train to match the y_t, False if the network should ignore y_t when training.
  201. """
  202. # ----------------------------------
  203. # Initialize with noise
  204. # ----------------------------------
  205. x_t = np.sqrt(2*.01*np.sqrt(10)*np.sqrt(self.dt)*params['stim_noise']*params['stim_noise'])*np.random.randn(self.N_in)
  206. y_t = np.zeros(self.N_out)
  207. mask_t = np.zeros(self.N_out)
  208. # ----------------------------------
  209. # Retrieve parameters
  210. # ----------------------------------
  211. # --- timeline params
  212. stimulus_1 = params['stimulus_1']
  213. delay_1 = params['delay_1']
  214. stimulus_2 = params['stimulus_2']
  215. delay_2 = params['delay_2']
  216. decision = params['decision']
  217. end = params['end']
  218. #--- task params
  219. cue_position = params['cue_position']
  220. target_position = params['target_position']
  221. detection = params['detection']
  222. gain = params['attention_gain']
  223. target_indensity = params['target_indensity']
  224. cue_indensity = 0.3
  225. # ----------------------------------
  226. # Compute values
  227. # ----------------------------------
  228. if stimulus_1 <= time < delay_1:
  229. x_t[cue_position] += cue_indensity + np.random.normal(0, 0.05)
  230. x_t[1-cue_position] += np.random.normal(0, 0.05)
  231. if stimulus_2 <= time < delay_2:
  232. if target_position == cue_position:
  233. x_t[target_position] += target_indensity * detection * gain + np.random.normal(0, 0.05)
  234. x_t[1-target_position] += np.random.normal(0, 0.05)
  235. else:
  236. x_t[target_position] += target_indensity * detection + np.random.normal(0, 0.05)
  237. x_t[1-target_position] += np.random.normal(0, 0.05) * gain
  238. if decision + 20 < time < end:
  239. y_t[0] = (1-target_position) * detection
  240. y_t[1] = target_position * detection
  241. mask_t = np.ones(self.N_out)
  242. return x_t, y_t, mask_t
  243. # this function doesn't used by training loss
  244. def accuracy_function(self, correct_output, test_output, output_mask):
  245. """Calculates the accuracy of :data:`test_output`.
  246. Implements :func:`~psychrnn.tasks.task.Task.accuracy_function`.
  247. Takes the channel-wise mean of the masked output for each trial. Whichever channel has a greater mean is considered to be the network's "choice".
  248. Returns:
  249. float: 0 <= accuracy <= 1. Accuracy is equal to the ratio of trials in which the network made the correct choice as defined above.
  250. """
  251. m_start = np.nonzero(output_mask[0]==1)[0][0] # find the start of mask
  252. m_end = np.nonzero(output_mask[0]==1)[0][-1] # find the end of mask
  253. output_raw = np.mean(test_output[:,m_start:m_end,:], axis=1)
  254. output_raw[output_raw >= 0.5] = 1 # transfer output to binary value
  255. output_raw[output_raw < 0.5] = 0
  256. correct_y = np.mean(correct_output[:,m_start:m_end,:], axis=1)
  257. return np.mean([(output_raw[idx] == correct_y[idx]).all() for idx in range(np.shape(output_raw)[0])])
  258. # this function doesn't used by training loss
  259. def accuracy_function_seen(self, correct_output, test_output, output_mask):
  260. """Calculates the accuracy of :data:`test_output`.
  261. Discrimination task for the
  262. Implements :func:`~psychrnn.tasks.task.Task.accuracy_function`.
  263. Takes the channel-wise mean of the masked output for each trial. Whichever channel has a greater mean is considered to be the network's "choice".
  264. Returns:
  265. float: 0 <= accuracy <= 1. Accuracy is equal to the ratio of trials in which the network made the correct choice as defined above.
  266. """
  267. chosen = np.argmax(np.mean(test_output*output_mask, axis=1), axis = 1)
  268. truth = np.argmax(np.mean(correct_output*output_mask, axis = 1), axis = 1)
  269. return np.mean(np.equal(truth, chosen))
  270. ### Some utils functions
  271. def lesion_units(weights, units):
  272. """
  273. Lesion units: reset input, output weights and recurrent weights with other units to zero.
  274. units : can be None, an integer index, or a list of integer indices
  275. """
  276. if units is None:
  277. return weights
  278. else:
  279. units = np.array(units)
  280. # Input weights
  281. weights['W_in'][units,:] = 0
  282. # output weights
  283. for i in range(np.shape(weights['W_out'])[0]):
  284. weights['W_out'][i][units] = 0
  285. # recurrent weights
  286. weights['W_rec'][units, :] = 0
  287. return weights
  288. def test_model_acc(ExocosModel, basicModel):
  289. """
  290. calculate accuracy of model
  291. """
  292. V_acc = []
  293. Inv_acc = []
  294. Absence_acc = []
  295. All_acc = []
  296. for i_batch in range(50):
  297. x,y,m, trial_params = ExocosModel.get_trial_batch()
  298. output, state_var = basicModel.test(x)
  299. Absence_idx = [];
  300. V_idx = [];
  301. Inv_idx = [];
  302. for i in range(50):
  303. if trial_params[i]['detection'] == 0:
  304. Absence_idx.append(i)
  305. elif trial_params[i]['cue_position'] == trial_params[i]['target_position']:
  306. V_idx.append(i)
  307. else:
  308. Inv_idx.append(i)
  309. V_acc.append(ExocosModel.accuracy_function(y[V_idx,:,:],output[V_idx,:,:],m[V_idx,:,:]))
  310. Inv_acc.append(ExocosModel.accuracy_function(y[Inv_idx,:,:],output[Inv_idx,:,:],m[Inv_idx,:,:]))
  311. Absence_acc.append(ExocosModel.accuracy_function(y[Absence_idx,:,:],output[Absence_idx,:,:],m[Absence_idx,:,:]))
  312. All_acc.append(ExocosModel.accuracy_function(y,output,m))
  313. return V_acc, Inv_acc,Absence_acc,All_acc
  314. def test_model_acc_seen(ExocosModel, basicModel):
  315. """
  316. calculate accuracy of model for perceiving validly and invalidly cued target
  317. """
  318. V_acc = []
  319. Inv_acc = []
  320. for i_batch in range(50):
  321. x,y,m, trial_params = ExocosModel.get_trial_batch()
  322. output, state_var = basicModel.test(x)
  323. V_idx = [];
  324. Inv_idx = [];
  325. for i in range(50):
  326. if trial_params[i]['detection'] == 0:
  327. pass
  328. elif trial_params[i]['cue_position'] == trial_params[i]['target_position']:
  329. V_idx.append(i)
  330. else:
  331. Inv_idx.append(i)
  332. V_acc.append(ExocosModel.accuracy_function_seen(y[V_idx,:,:],output[V_idx,:,:],m[V_idx,:,:]))
  333. Inv_acc.append(ExocosModel.accuracy_function_seen(y[Inv_idx,:,:],output[Inv_idx,:,:],m[Inv_idx,:,:]))
  334. return [V_acc, Inv_acc]
  335. def plot_sample(trlnum,x,y,m, trial_params,output,state_var):
  336. """
  337. plot trial sample to check the state variables
  338. """
  339. trl = trlnum # plot trial num
  340. print("cue_position :", trial_params[trl]['cue_position'])
  341. print("target_position : ", trial_params[trl]['target_position'])
  342. print("detection : ", trial_params[trl]['detection'])
  343. fig = plt.gcf()
  344. fig.set_size_inches(6, 4)
  345. ax1 = plt.subplot(311)
  346. plt.plot(range(0, len(x[0,:,:])*dt,dt), x[trl,:,:])
  347. plt.ylabel("Stim intensity")
  348. plt.legend(["Input 1", "Input 2"])
  349. plt.ylim(-0.2, 0.6)
  350. plt.setp(ax1.get_xticklabels(), visible=False)
  351. # share x only
  352. ax2 = plt.subplot(312, sharex=ax1)
  353. plt.plot(range(0, len(x[0,:,:])*dt,dt), y[trl,:,:])
  354. plt.ylabel("Target presence")
  355. plt.legend(["y1","y2"])
  356. # make these tick labels invisible
  357. plt.setp(ax2.get_xticklabels(), visible=False)
  358. plt.ylim(-0.2, 1.5)
  359. # share x and y
  360. ax3 = plt.subplot(313, sharex=ax1)
  361. plt.plot(range(0, len(x[0,:,:])*dt,dt), m[trl,:,:])
  362. plt.ylabel("Decision mask")
  363. plt.xlabel("Time (ms)")
  364. plt.legend(["Mask1", "Mask2"])
  365. plt.ylim(-0.2, 1.5)
  366. plt.show()
  367. fig = plt.gcf()
  368. fig.set_size_inches(6, 4)
  369. ax1 = plt.subplot(211)
  370. plt.plot(range(0, len(output[0,:,:])*dt,dt),output[trl,:,:])
  371. plt.ylabel("Activity of Output Unit")
  372. plt.title("Target detection strength")
  373. plt.legend(["Output 1", "Output 2"])
  374. plt.setp(ax1.get_xticklabels(), visible=False)
  375. ax2 = plt.subplot(212)
  376. plt.plot(range(0, len(state_var[0,:,:])*dt,dt),state_var[trl,:,:])
  377. plt.ylabel("State Variable Value")
  378. plt.xlabel("Time (ms)")
  379. plt.title("Evolution of State Variables over Time")
  380. plt.show()
  381. # %% [markdown]
  382. # ## 3 - Model training
  383. # %% [markdown]
  384. # ### model parameters
  385. # %%
  386. dt = 10 # The simulation timestep.
  387. tau = 100 # The intrinsic time constant of neural state decay.
  388. T = 1600 # The trial length.
  389. N_batch = 50 # The number of trials per training update.
  390. N_rec = 50 # The number of recurrent units in the network.
  391. name = 'ExocosModel' # Unique name used to determine variable scope for internal use.
  392. ExocosModel = ExogenousAttention(target_indensity = 0.10, dt = dt, tau = tau, T = T, N_batch = N_batch, attention_gain = 1.5)
  393. ## Initialize Model
  394. network_params = ExocosModel.get_task_params()
  395. ##----------
  396. # Network params
  397. ##----------
  398. network_params['dale_ratio'] = 0.8
  399. network_params['name'] = name # Unique name used to determine variable scope.
  400. network_params['N_rec'] = N_rec # The number of recurrent units in the network.
  401. network_params['rec_noise'] = 0.05 # Noise into each recurrent unit. Default: 0.0
  402. network_params['W_in_train'] = True # Indicates whether W_in is trainable. Default: True
  403. network_params['W_rec_train'] = True # Indicates whether W_rec is trainable. Default: True
  404. network_params['W_out_train'] = True # Indicates whether W_out is trainable. Default: True
  405. network_params['b_rec_train'] = True # Indicates whether b_rec is trainable. Default: True
  406. network_params['b_out_train'] = True # Indicates whether b_out is trainable. Default: True
  407. network_params['init_state_train'] = True # Indicates whether init_state is trainable. Default: True
  408. network_params['transfer_function'] = tf.nn.relu # Transfer function to use for the network. Default: tf.nn.relu.
  409. network_params['loss_function'] = "mean_squared_error"# String indicating what loss function to use. If not `mean_squared_error` or `binary_cross_entropy`, params["loss_function"] defines the custom loss function. Default: "mean_squared_error".
  410. network_params['load_weights_path'] = None # When given a path, loads weights from file in that path. Default: None
  411. # network_params['initializer'] = # Initializer to use for the network. Default: WeightInitializer (network_params) if network_params includes W_rec or load_weights_path as a key, GaussianSpectralRadius (network_params) otherwise.
  412. network_params['which_rand_init'] = 'glorot_gauss' # Which random initialization to use for W_in and W_out. Will also be used for W_rec if which_rand_W_rec_init is not passed in. Options: 'const_unif', 'const_gauss', 'glorot_unif', 'glorot_gauss'. Default: 'glorot_gauss'.
  413. network_params['which_rand_W_rec_init'] = network_params['which_rand_init'] # 'Which random initialization to use for W_rec. Options: 'const_unif', 'const_gauss', 'glorot_unif', 'glorot_gauss'. Default: which_rand_init.
  414. network_params['init_minval'] = -.1 # Used by const_unif_init() as minval if 'const_unif' is passed in for which_rand_init or which_rand_W_rec_init. Default: -.1.
  415. network_params['init_maxval'] = .1 # Used by const_unif_init() as maxval if 'const_unif' is passed in for which_rand_init or which_rand_W_rec_init. Default: .1.
  416. ####-----------------------
  417. # Regularization Parameters
  418. ### -----------------------
  419. network_params['L1_in'] = 0 # Parameter for weighting the L1 input weights regularization. Default: 0.
  420. network_params['L1_rec'] = 0 # Parameter for weighting the L1 recurrent weights regularization. Default: 0.
  421. network_params['L1_out'] = 0 # Parameter for weighting the L1 output weights regularization. Default: 0.
  422. network_params['L2_in'] = 0 # Parameter for weighting the L2 input weights regularization. Default: 0.
  423. network_params['L2_rec'] = 0 # Parameter for weighting the L2 recurrent weights regularization. Default: 0.
  424. network_params['L2_out'] = 0 # Parameter for weighting the L2 output weights regularization. Default: 0.
  425. network_params['L2_firing_rate'] = 0 # Parameter for weighting the L2 regularization of the relu thresholded states. Default: 0.
  426. network_params['custom_regularization'] = None # Custom regularization function. Default: None.
  427. # %% [markdown]
  428. # ### Option: Training parameters (to re-train the model)
  429. # %%
  430. ## define a model instance and initialization
  431. basicModel = Basic(network_params)
  432. # Set the training parameters for our model.
  433. train_params = {}
  434. train_params['save_weights_path'] = None # Where to save the model after training. Default: None
  435. train_params['training_iters'] = 150000 # number of iterations to train for Default: 50000
  436. train_params['learning_rate'] = .001 # Sets learning rate if use default optimizer Default: .001
  437. train_params['loss_epoch'] = 10 # Compute and record loss every 'loss_epoch' epochs. Default: 10
  438. train_params['verbosity'] = True # If true, prints information as training progresses. Default: True
  439. train_params['save_training_weights_epoch'] = 100 # save training weights every 'save_training_weights_epoch' epochs. Default: 100
  440. train_params['training_weights_path'] = None # where to save training weights as training progresses. Default: None
  441. train_params['optimizer'] = tf.compat.v1.train.AdamOptimizer(learning_rate=train_params['learning_rate']) # What optimizer to use to compute gradients. Default: tf.train.AdamOptimizer(learning_rate=train_params['learning_rate'])
  442. train_params['clip_grads'] = True # If true, clip gradients by norm 1. Default: True
  443. train_params['fixed_weights'] = None # Dictionary of weights to fix (not allow to train). Default: None
  444. ## Example usage of the optional performance_cutoff and performance_measure parameters is available in Curriculum Learning tutorial.
  445. train_params['performance_cutoff'] = None # If performance_measure is not None, training stops as soon as performance_measure surpases the performance_cutoff. Default: None.
  446. train_params['performance_measure'] = None # Function to calculate the performance of the network using custom criteria. Default: None.]
  447. # %%
  448. ## model training
  449. losses, initialTime, trainTime = basicModel.train(ExocosModel, train_params)
  450. # %%
  451. plt.plot(losses)
  452. plt.ylabel("Loss")
  453. plt.xlabel("Training Iteration")
  454. plt.title("Loss During Training")
  455. # %%
  456. basicModel.save("./drive/MyDrive/Colab Notebooks/TrainedModelStates/ExocosTrainedModels__I150000_Target0p10_Gain1p5_summary")
  457. # %% [markdown]
  458. # ### Option: Load trained model
  459. # %%
  460. ## load trained model to reproduce the figures
  461. load_network_params = network_params.copy()
  462. load_network_params['load_weights_path'] = './drive/MyDrive/Colab Notebooks/TrainedModelStates/ExocosTrainedModels__I150000_' + 'Target0p10_Gain1p5_summary' + '.npz'
  463. basicModel = Basic(load_network_params)
  464. # %% [markdown]
  465. # ## 4 - Model probing and trial sample
  466. # %% [markdown]
  467. # ### target intensity
  468. # %%
  469. V_param = [];
  470. Inv_param = [];
  471. Absence_param = [];
  472. All_param = [];
  473. prob_intensity = np.arange(0.00,0.13,0.01)
  474. for this_intensity in prob_intensity:
  475. ExocosModel = ExogenousAttention(dt = dt, tau = tau, T = T, N_batch = N_batch, target_indensity = this_intensity) # Initialize the task object
  476. V_acc, Inv_acc,Absence_acc,All_acc = test_model_acc(ExocosModel,basicModel)
  477. print("Computing : " + "{:.2f}".format(this_intensity))
  478. V_param.append(V_acc)
  479. Inv_param.append(Inv_acc)
  480. Absence_param.append(Absence_acc)
  481. All_param.append(All_acc)
  482. # %%
  483. target_indensities = prob_intensity
  484. fig = plt.figure(figsize=(2, 3))
  485. ax = fig.add_axes([0.3,0.2, 0.6, 0.6])
  486. ax.plot(target_indensities,np.mean(All_param,axis=1) * 100, linewidth= 3, color = 'black')
  487. text_font = 10
  488. plt.xlabel('Target intensity [a.u.]', fontsize=text_font)
  489. plt.ylabel('Accuracy [%]', fontsize=text_font)
  490. plt.title('Target performance', fontsize=text_font, y=1)
  491. plt.locator_params(axis='y', nbins=2)
  492. ax.tick_params(axis='both', which='major', labelsize=8, length=1)
  493. ax.spines["right"].set_visible(False)
  494. ax.spines["top"].set_visible(False)
  495. ax.xaxis.set_ticks_position('bottom')
  496. ax.yaxis.set_ticks_position('left')
  497. # plt.savefig('./drive/MyDrive/Colab Notebooks/figure/Performance_turning_target0p10.png',dpi = 300)
  498. # %% [markdown]
  499. # ### Trials sample and units state variables
  500. # %%
  501. this_target = 0.10
  502. ExocosModel = ExogenousAttention(target_indensity= this_target, dt = dt, tau = tau, T = T, N_batch = N_batch, attention_gain = 1.5) # Initialize the task object
  503. # generate testing trial batch
  504. x,y,m, trial_params = ExocosModel.get_trial_batch()
  505. # generate testing output from trained models
  506. output, state_var = basicModel.test(x)
  507. # %%
  508. trial_params
  509. # %%
  510. ## save to Matlab format for reproductibility
  511. output_struct = {"x":x,
  512. "y":y,
  513. "m":m,
  514. "trial_params":trial_params,
  515. "output": output,
  516. "state_var":state_var
  517. }
  518. scipy.io.savemat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/Exocos_RNN_output_trial_examples', output_struct)
  519. # %%
  520. # reproductibility of figure
  521. trial_example = scipy.io.loadmat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/Exocos_RNN_output_trial_examples')
  522. x = trial_example['x']
  523. state_var = trial_example['state_var']
  524. output = trial_example['output']
  525. # %%
  526. from matplotlib.patches import Rectangle
  527. trl = 49 # invalid : 1# valid : 5 # absence : 49 # plot trial num
  528. print("cue_position :", trial_params[trl]['cue_position'])
  529. print("target_position : ", trial_params[trl]['target_position'])
  530. print("detection : ", trial_params[trl]['detection'])
  531. text_font = 10
  532. tick_font = 10
  533. fig = plt.figure(figsize=(4, 6))
  534. ax = fig.add_axes([0.3,0.2, 0.6, 0.8])
  535. ax = plt.subplot(311)
  536. plt.plot(range(0, len(x[0,:,0])*dt,dt), x[trl,:,0], linewidth=2, color=(21/255,163/255,205/255))
  537. plt.plot(range(0, len(x[0,:,1])*dt,dt), x[trl,:,1], linewidth=2, color=(221/255,102/255,155/255))
  538. plt.ylabel("Stim input (a.u.)", fontsize=text_font)
  539. plt.legend(["left side", "right side"], fontsize=text_font, frameon=False, bbox_to_anchor=(0.1, 0.9, 1., .1))
  540. ylim = (-0.3, 0.5)
  541. plt.ylim(ylim)
  542. plt.xlim(0, 1500)
  543. plt.axvline(x=190, color = 'k', ls='--',linewidth=0.8)
  544. plt.axvline(x=560, color = 'k', ls='-', linewidth=0.8)
  545. start_mask = np.where(m[0,:,0] == 1)[0][0]
  546. end_mask = np.where(m[0,:,0] == 1)[0][-1]
  547. plt.text(190, 0.52, 'Cue', ha='center', va='bottom', fontsize =10)
  548. plt.text(560, 0.52, 'Target', ha='center', va='bottom', fontsize =10)
  549. plt.text(start_mask*10+40, 0.52, 'Response', ha='center', va='bottom', fontsize =10)
  550. rect = Rectangle((start_mask*10, ylim[0]), (end_mask - start_mask) *10 , ylim[1] - ylim[0] ,color='gray',alpha = 0.2 )
  551. ax.add_patch(rect)
  552. plt.locator_params(axis='y', nbins=2)
  553. ax.tick_params(axis='both', which='major', labelsize=tick_font, length=1)
  554. ax.spines["right"].set_visible(False)
  555. ax.spines["top"].set_visible(False)
  556. ax.xaxis.set_ticks_position('bottom')
  557. ax.yaxis.set_ticks_position('left')
  558. plt.setp(ax.get_xticklabels(), visible=False)
  559. # share x - plot state variables
  560. ax2 = plt.subplot(312, sharex=ax)
  561. plt.plot(range(0, len(state_var[0,:,:])*dt,dt),state_var[trl,:,:],linewidth=0.5, color='gray')
  562. plt.ylabel("Units state (a.u.)")
  563. plt.ylim(-2,2)
  564. plt.locator_params(axis='y', nbins=2)
  565. ax2.tick_params(axis='both', which='major', labelsize=tick_font, length=1)
  566. ax2.spines["right"].set_visible(False)
  567. ax2.spines["top"].set_visible(False)
  568. ax2.xaxis.set_ticks_position('bottom')
  569. ax2.yaxis.set_ticks_position('left')
  570. plt.setp(ax2.get_xticklabels(), visible=False)
  571. # share x - plot output
  572. ax3 = plt.subplot(313, sharex=ax)
  573. plt.plot(range(0, len(output[0,:,0])*dt,dt), output[trl,:,0], linewidth=2, color=(21/255,163/255,205/255))
  574. plt.plot(range(0, len(output[0,:,1])*dt,dt), output[trl,:,1], linewidth=2, color=(221/255,102/255,155/255))
  575. plt.ylabel("Network output (a.u.)")
  576. plt.legend(["left side", "right side"], fontsize=text_font, frameon=False)
  577. plt.ylim(-0.2,1.5)
  578. plt.locator_params(axis='y', nbins=3)
  579. ax3.tick_params(axis='both', which='major', labelsize=tick_font, length=1)
  580. ax3.spines["right"].set_visible(False)
  581. ax3.spines["top"].set_visible(False)
  582. ax3.xaxis.set_ticks_position('bottom')
  583. ax3.yaxis.set_ticks_position('left')
  584. plt.xlabel("Time [ms]")
  585. plt.savefig('./drive/MyDrive/Colab Notebooks/figure/RNN_task_represent_absent.pdf',dpi = 300)
  586. #plt.savefig('./drive/MyDrive/Colab Notebooks/figure/RNN_task_represent_valid.pdf',dpi = 300)
  587. #plt.savefig('./drive/MyDrive/Colab Notebooks/figure/RNN_task_represent_invalid.pdf',dpi = 300)
  588. # %% [markdown]
  589. # ## 5 - PCA/t-SNE analysis to investigate task representation
  590. # %% [markdown]
  591. # ### generate new trials samples and trained output
  592. # %%
  593. from sklearn.decomposition import PCA
  594. from sklearn.manifold import TSNE
  595. targetlevel = ["low","intermediate","high"]
  596. this_targets = [0.01, 0.20, 0.30] # probing contrast
  597. Label_Detection_all = []
  598. state_var_all = []
  599. for this_target in this_targets:
  600. ExocosModel = ExogenousAttention(target_indensity= this_target, dt = dt, tau = tau, T = T, N_batch = N_batch, attention_gain = 1.5)
  601. # create labels and trials samples
  602. Label_Detection = []
  603. Label_Interaction = []
  604. state_var_concate = np.zeros((0,0,0))
  605. target_name = ['no target', 'seen valid', 'seen inv']
  606. # 0 : no target
  607. # 1 : detected / SV
  608. # 2 : SIv
  609. for trialblock in range(20): # 20 blocks * 50 trials = 1000 trials
  610. x,y,m, trial_params = ExocosModel.get_trial_batch()
  611. # generate testing output from trained models
  612. output, state_var = basicModel.test(x)
  613. if trialblock == 0:
  614. state_var_concate = state_var
  615. else:
  616. state_var_concate = np.concatenate((state_var_concate,state_var),axis=0)
  617. for i, this_trial in enumerate(trial_params):
  618. if this_trial['detection'] == 0:
  619. Label_Detection.append(0)
  620. elif this_trial['cue_position'] == this_trial['target_position']:
  621. Label_Detection.append(1)
  622. else:
  623. Label_Detection.append(2)
  624. print(np.shape(Label_Detection))
  625. print(np.shape(state_var_concate))
  626. Label_Detection_all.append(Label_Detection)
  627. state_var_all.append(state_var_concate)
  628. ## save to Matlab format
  629. output_struct = {"Label_Detection_all":Label_Detection_all,
  630. "state_var_all":state_var_all,
  631. "experiment": "exocos_RNN",
  632. }
  633. scipy.io.savemat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/Exocos_RNN_output_1000trialexamples.mat', output_struct)
  634. # %%
  635. data_alloc = scipy.io.loadmat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/Exocos_RNN_output_1000trialexamples.mat')
  636. Label_Detection_all = data_alloc['Label_Detection_all']
  637. state_var_all = data_alloc['state_var_all']
  638. # %% [markdown]
  639. # ##### prepare data for autoencoder only
  640. # %%
  641. ## take some outputs to train Autoencoder.
  642. from sklearn.decomposition import PCA
  643. from sklearn.manifold import TSNE
  644. x_all = []
  645. y_all = []
  646. m_all = []
  647. trial_params_all = []
  648. # creat model instance
  649. ExocosModel = ExogenousAttention(target_indensity= this_target, dt = dt, tau = tau, T = T, N_batch = N_batch, attention_gain = 1.5)
  650. for trialblock in range(20): # 20 blocks * 50 trials = 1000 trials
  651. x,y,m, trial_params = ExocosModel.get_trial_batch()
  652. # generate testing output from trained models
  653. # output, state_var = basicModel.test(x)
  654. x_all.append(x)
  655. y_all.append(y)
  656. m_all.append(m)
  657. trial_params_all.append(trial_params)
  658. ## save to Matlab format
  659. output_struct = {"data_mat_input":x_all,
  660. "data_mat_output":y_all,
  661. "experiment": "exocos_RNN",
  662. }
  663. scipy.io.savemat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/Exocos_RNN_output_trained0p1_target0p10InterInputsMat.mat', output_struct)
  664. # %%
  665. data_mat= scipy.io.loadmat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/Exocos_RNN_output_trained0p1_target0p10InterInputsMat.mat')
  666. # %% [markdown]
  667. # ### PCA ploting
  668. # %%
  669. fig = plt.figure(figsize=(8, 4))
  670. for i_level in range(3):
  671. # Calculate mean or variance
  672. X = np.var(state_var_all[i_level], axis = 2)
  673. y = np.array(Label_Detection_all[i_level])
  674. model = PCA(n_components=2)
  675. X_r = model.fit_transform(X)
  676. # Percentage of variance explained for each components
  677. print('explained variance ratio (first two components): %s' % str(model.explained_variance_ratio_))
  678. target_names = ['No target', 'Seen V', 'Seen Inv']
  679. colors = ['navy', (21/255,163/255,205/255), (221/255,102/255,155/255)]
  680. lw = 2
  681. ax = fig.add_axes([0.1, 0.2, 0.6, 0.8])
  682. ax = plt.subplot(1,3,i_level+1)
  683. for color, i, target_name in zip(colors, [0, 1, 2], target_names):
  684. plt.scatter(X_r[y == i, 0], X_r[y == i, 1], color=color, lw=lw,
  685. label=target_name)
  686. if i_level > 1:
  687. plt.legend(loc='best', shadow=False, scatterpoints=1, fontsize = 12, frameon=False, bbox_to_anchor=(0.8, 0.7, 1., .1))
  688. plt.xlim(-3, 4)
  689. plt.ylim(-2, 2)
  690. plt.text(0, 1.3, targetlevel[i_level], ha='center', va='bottom', fontsize = 15)
  691. ax.axis('off')
  692. plt.savefig('./drive/MyDrive/Colab Notebooks/figure/pca.pdf',dpi = 300)
  693. # plt.locator_params(axis='y', nbins=2)
  694. # ax.tick_params(axis='both', which='major', labelsize=tick_font, length=1)
  695. #ax.spines["right"].set_visible(False)
  696. #ax.spines["top"].set_visible(False)
  697. #ax.xaxis.set_ticks_position('bottom')
  698. #ax.yaxis.set_ticks_position('left')
  699. # plt.setp(ax.get_xticklabels(), visible=False)
  700. # %% [markdown]
  701. # ### t-SNE ploting
  702. # %%
  703. fig = plt.figure(figsize=(8, 3))
  704. for i_level in range(3):
  705. # Calculate mean or variance
  706. X = np.var(state_var_all[i_level], axis = 2)
  707. y = np.array(Label_Detection_all[i_level])
  708. model = TSNE(n_components=2, random_state=0, init='pca',
  709. verbose=1, method='exact',
  710. learning_rate=100, perplexity=30)
  711. X_r = model.fit_transform(X)
  712. # Percentage of variance explained for each components
  713. target_names = ['no target', 'seen valid', 'seen invalid']
  714. colors = ['navy', (21/255,163/255,205/255), (221/255,102/255,155/255)]
  715. lw = 2
  716. ax = fig.add_axes([0.2, 0.2, 0.6, 0.8])
  717. ax = plt.subplot(1,3,i_level+1)
  718. for color, i, target_name in zip(colors, [0, 1, 2], target_names):
  719. plt.scatter(X_r[y == i, 0], X_r[y == i, 1], color=color, lw=lw,
  720. label=target_name)
  721. if i_level > 1:
  722. plt.legend(loc='best', shadow=False, scatterpoints=1, fontsize = 12, frameon=False, bbox_to_anchor=(0.9, 0.5, 1., .1))
  723. plt.xlim(-90, 90)
  724. plt.ylim(-80, 80)
  725. plt.text(0, 70, targetlevel[i_level], ha='center', va='bottom', fontsize = 15)
  726. ax.axis('off')
  727. plt.savefig('./drive/MyDrive/Colab Notebooks/figure/t-sne.pdf',dpi = 300)
  728. # %%
  729. import sklearn
  730. # %% [markdown]
  731. # ### Dynamic ploting
  732. # %%
  733. fig = plt.figure(figsize=(8,8))
  734. plot_order = [0,3,6,1,4,7,2,5,8]
  735. count = 0
  736. for i_level in range(3):
  737. for i, cond in enumerate(target_names):
  738. X = np.var(state_var_all[i_level], axis = 2)
  739. y = np.array(Label_Detection_all[i_level])
  740. X_i = X[y == i]
  741. # calculate PCA
  742. model = PCA(n_components = 2).fit(X_i.T)
  743. # visualize first and second PC
  744. W = model.components_
  745. pc_score = W @ X_i
  746. ax = fig.add_axes([0.3, 0.2, 0.6, 0.8])
  747. ax = plt.subplot(3,3,plot_order[count]+1)
  748. count+=1
  749. c = np.array(range(pc_score.shape[1]))
  750. s = np.ones(pc_score.shape[1]) * 20
  751. s[20] = 150;
  752. s[56] = 150;
  753. s[95] = 150;
  754. plt.scatter(pc_score[0,:],pc_score[1,:],s = s, c = c,marker='o' )
  755. cmap = plt.set_cmap('hot')
  756. plt.title(cond)
  757. plt.xlim([-2,18.8])
  758. plt.ylim([-1.5,2])
  759. ax.axis('off')
  760. plt.savefig('./drive/MyDrive/Colab Notebooks/figure/dynamic.pdf',dpi = 300)
  761. # %%
  762. fig, ax = plt.subplots(figsize=(5,3))
  763. X = np.var(state_var_all[0], axis = 2)
  764. y = np.array(Label_Detection_all[0])
  765. X_i = X[y == i]
  766. # calculate PCA
  767. model = PCA(n_components = 2).fit(X_i.T)
  768. # visualize first and second PC
  769. W = model.components_
  770. pc_score = W @ X_i
  771. cax = ax.scatter(pc_score[0,:],pc_score[1,:],c = np.array(range(pc_score.shape[1]))*10)
  772. cmap = plt.set_cmap('hot')
  773. plt.xlim([-2,17])
  774. plt.ylim([-1,2])
  775. ax.axis('off')
  776. cbar = fig.colorbar(cax, ticks=[200, 560, 950], aspect = 15)
  777. cbar.ax.set_yticklabels(['Cue', 'Target', 'Resp']) # vertically oriented colorbar
  778. plt.savefig('./drive/MyDrive/Colab Notebooks/figure/colorbar.pdf',dpi = 300)
  779. # %% [markdown]
  780. # ## 6 - Trajectory k-mean method about temporal dynamics
  781. # %% [markdown]
  782. # ### Prepare trials and k-means input
  783. # %%
  784. # change the dim order of the input matrix -> Units * timesteps * conditions
  785. state_var_reordered = np.transpose(state_var_concate, (2, 1, 0))
  786. y_label = np.array(Label_Detection)
  787. CombinedTrials = [np.mean(state_var_reordered[:,:,y_label == i_cond],axis = 2) for i_cond in range(3)]
  788. keam_input_mat = np.transpose(CombinedTrials, (1,2,0))
  789. ## save to Matlab format
  790. output_struct = {"data_mat":keam_input_mat,
  791. "experiment": "exocos_RNN",
  792. "state_var_units": state_var_concate,
  793. "label_trial": Label_Detection,
  794. "labels" : "0: no target, 1: Seen V, 2: Seen Iv"}
  795. scipy.io.savemat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/Exocos_RNN_output_trained0p1_target0p10Inter.mat', output_struct)
  796. # %%
  797. id_clust = [2,4,2,2,1,3,1,1,4,1,5,1,2,5,4,2,2,4,5,2,1,1,2,5,2,5,2,1,4,4,5,2,2,2,2,2,2,5,5,3,2,2,1,4,2,4,2,3,1,1]
  798. # %% [markdown]
  799. # ## 7 - PCA/t-SNE analysis on RNN cluster
  800. # %%
  801. ## load electrod id in each cluster, for reproductibility
  802. id_clust = scipy.io.loadmat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/clust_id_0p10_k5.mat')['id'][0]
  803. # id_clust = [2,4,2,2,1,3,1,1,4,1,5,1,2,5,4,2,2,4,5,2,1,1,2,5,2,5,2,1,4,4,5,2,2,2,2,2,2,5,5,3,2,2,1,4,2,4,2,3,1,1]
  804. # %%
  805. #####
  806. # generate test trial samples
  807. #####
  808. targetlevel = ["low","intermediate","high"]
  809. this_targets = [0.01, 0.15, 0.30] # probing contrast
  810. Label_Detection_all = []
  811. state_var_all = []
  812. for this_target in this_targets:
  813. ExocosModel = ExogenousAttention(target_indensity= this_target, dt = dt, tau = tau, T = T, N_batch = N_batch, attention_gain = 1.5)
  814. # create labels and trials samples
  815. Label_Detection = []
  816. Label_Interaction = []
  817. state_var_concate = np.zeros((0,0,0))
  818. target_name = ['no target', 'seen valid', 'seen inv']
  819. # 0 : no target
  820. # 1 : detected / S V
  821. # 2 : detected / S Iv
  822. for trialblock in range(20): # 20 blocks * 50 trials = 1000 trials
  823. x,y,m, trial_params = ExocosModel.get_trial_batch()
  824. # generate testing output from trained models
  825. output, state_var = basicModel.test(x)
  826. if trialblock == 0:
  827. state_var_concate = state_var
  828. else:
  829. state_var_concate = np.concatenate((state_var_concate,state_var),axis=0)
  830. for i, this_trial in enumerate(trial_params):
  831. if this_trial['detection'] == 0:
  832. Label_Detection.append(0)
  833. elif this_trial['cue_position'] == this_trial['target_position']:
  834. Label_Detection.append(1)
  835. else:
  836. Label_Detection.append(2)
  837. Label_Detection_all.append(Label_Detection)
  838. state_var_all.append(state_var_concate)
  839. print(np.shape(Label_Detection_all))
  840. print(np.shape(state_var_all))
  841. # %%
  842. plot_order = [0,5,10,1,6,11,2,7,12,3,8,13,4,9,14]
  843. clust_to_plots = [5,2,4,1,3]
  844. target_names = ['no target', 'seen valid', 'seen invalid']
  845. for i_level in range(3):
  846. fig = plt.figure(figsize=(10,6))
  847. count = 0
  848. state_var_this_level = state_var_all[i_level]
  849. Label_Detection_this_level = Label_Detection_all[i_level]
  850. for i_cst, cst in enumerate(clust_to_plots):
  851. for i, cond in enumerate(target_names):
  852. X = np.mean(state_var_this_level[:,:,id_clust == cst], axis = 2) # trial * time * units
  853. y = np.array(Label_Detection_this_level)
  854. X_i = X[y == i]
  855. # calculate PCA
  856. model = PCA(n_components = 2).fit(X_i.T)
  857. # visualize first and second PC
  858. W = model.components_
  859. pc_score = W @ X_i
  860. ax = fig.add_axes([0.2, 0.2, 0.6, 0.8])
  861. ax = plt.subplot(3,5,plot_order[count]+1)
  862. count+=1
  863. c = np.array(range(pc_score.shape[1]))
  864. s = np.ones(pc_score.shape[1]) * 20
  865. s[20] = 150;
  866. s[56] = 150;
  867. s[95] = 150;
  868. plt.scatter(pc_score[0,:],pc_score[1,:],s = s, c = c,marker='o' )
  869. cmap = plt.set_cmap('hot')
  870. plt.title(cond)
  871. plt.xlim([-10,13])
  872. plt.ylim([-4,4])
  873. if i_cst == 1:
  874. plt.xlim([-5,15])
  875. plt.ylim([-4,4])
  876. if i_cst == 2:
  877. plt.xlim([-10,17])
  878. plt.ylim([-4,4])
  879. if i_cst == 3:
  880. plt.xlim([-11,13])
  881. plt.ylim([-5,6])
  882. if i_cst == 4:
  883. plt.xlim([-8,35])
  884. plt.ylim([-4,6])
  885. ax.axis('off')
  886. plt.savefig('./drive/MyDrive/Colab Notebooks/figure/RNN_clust_dynamic' + str(this_targets[i_level]) + '.pdf',dpi = 300)
  887. # %% [markdown]
  888. # ## 8 - lesion analysis by cluster
  889. # %%
  890. id_clust = scipy.io.loadmat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/clust_id_0p10_k5.mat')['id'][0]
  891. # clust ID for each units from clustering results, copy from Matlab
  892. # id_clust = [2,4,2,2,1,3,1,1,4,1,5,1,2,5,4,2,2,4,5,2,1,1,2,5,2,5,2,1,4,4,5,2,2,2,2,2,2,5,5,3,2,2,1,4,2,4,2,3,1,1]
  893. # %% [markdown]
  894. # #### Accuracy for detection task
  895. # %%
  896. #############################################
  897. #
  898. # PLOT valid invalid and absent and all
  899. #
  900. #############################################
  901. ### find the accuracy of model for SEEN valid and invalid seperately, binary comparison
  902. basicModel.destruct()
  903. cst_to_plot = [0.01, 0.05, 0.10, 0.20, 0.30,0.4, 0.5, 0.6, 0.7]
  904. acc_all = []
  905. for i_cst, this_target_intensity in enumerate(cst_to_plot):
  906. print(this_target_intensity)
  907. # Define probing target intensity
  908. ExocosModel = ExogenousAttention(target_indensity= this_target_intensity, dt = dt, tau = tau, T = T, N_batch = N_batch, attention_gain = 1.5)
  909. # order [5,2,4,1,3]
  910. clust_to_lesion = [None,5,2,4,1,3]
  911. acc = []
  912. for id_n,this_clust in enumerate(clust_to_lesion):
  913. # import trained model by importing its weights
  914. load_network_params = network_params.copy()
  915. load_network_params['load_weights_path'] = "./drive/MyDrive/Colab Notebooks/TrainedModelStates/ExocosTrainedModels__I150000_Target0p10_Gain1p5_summary.npz"
  916. TrainedModel = Basic(load_network_params)
  917. weights = TrainedModel.get_weights()
  918. TrainedModel.destruct()
  919. load_network_params = network_params.copy()
  920. # get units index in this cluster
  921. if this_clust is None:
  922. unit_indices = None
  923. else:
  924. unit_indices = [index for index, element in enumerate(id_clust) if element == this_clust]
  925. # modify weights in these units and reload a modified model
  926. weights_mod = lesion_units(weights, unit_indices)
  927. np.savez('./weights/modified_saved_weights.npz', **weights_mod)
  928. load_network_params['load_weights_path'] = './weights/modified_saved_weights.npz'
  929. ModifiedModel = Basic(load_network_params)
  930. # assessing the accuracy of lesioned model
  931. acc.append(test_model_acc(ExocosModel, ModifiedModel)[0:2])
  932. # destruct model once used
  933. ModifiedModel.destruct()
  934. acc_all.append(acc)
  935. ## save to Matlab format
  936. acc_detection_struct = {"data_mat":acc_all,
  937. "task": "discrimination",
  938. "labels" : "valid and invalid"}
  939. scipy.io.savemat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/Exocos_RNN_lesion_acc_detection.mat', acc_detection_struct)
  940. # %%
  941. acc_detect_raw = scipy.io.loadmat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/Exocos_RNN_lesion_acc_detection.mat')
  942. acc_detect = acc_detect_raw['data_mat']
  943. np.shape(acc_detect)
  944. clust_to_lesion = [None,5,2,4,1,3]
  945. # cst_to_plot = [0.01, 0.05, 0.10, 0.20, 0.30,0.4, 0.5, 0.6, 0.7]
  946. cst_to_plot = [0.01, 0.05, 0.10, 0.20, 0.30,0.4, 0.5, 0.6, 0.7]
  947. for id_cst, this_cst in enumerate(cst_to_plot):
  948. ## Calculate the average and std
  949. acc = acc_detect[id_cst]
  950. acc_mean = np.mean(acc, axis = 2).reshape((1, np.size(clust_to_lesion) * 2 )) # acc -> cluster * cond * block of 50
  951. acc_std = np.std(acc, axis = 2).reshape((1, np.size(clust_to_lesion) * 2 ))
  952. # Define labels, positions, bar heights and error bar heights
  953. labels = ['Intact', 'Visual', 'Sustain', 'Late', 'Reorient', 'Deactive']
  954. label_pos = np.arange(np.size(clust_to_lesion)) + 1
  955. x_pos = [(i+1-0.17,i+1+0.17) for i in range(len(clust_to_lesion))]
  956. x_pos = np.array(x_pos).reshape((1, np.size(clust_to_lesion) * 2 ))[0]
  957. CTEs = acc_mean[0]
  958. error = acc_std[0]
  959. # Build the plot
  960. fig = plt.figure(figsize=(2.5,2.5))
  961. ax = fig.add_axes([0.3,0.27, 0.6, 0.6])
  962. ax.bar(x_pos, CTEs,
  963. yerr=error,
  964. align='center',
  965. width=0.3,
  966. alpha=0.9,
  967. color = [(21/255,163/255,205/255), (221/255,102/255,155/255),(21/255,163/255,205/255), (221/255,102/255,155/255),
  968. (21/255,163/255,205/255), (221/255,102/255,155/255),(21/255,163/255,205/255), (221/255,102/255,155/255),
  969. (21/255,163/255,205/255), (221/255,102/255,155/255)],
  970. ecolor='black',
  971. capsize= 3)
  972. text_font = 10
  973. ax.set_xticks(label_pos)
  974. ax.set_xticklabels(labels, rotation = 45)
  975. plt.ylabel('Accuracy (%)', fontsize=text_font)
  976. plt.title('target contrast: ' + "{:.2f}".format(this_cst), fontsize=text_font, y=1.05)
  977. plt.locator_params(axis='y', nbins=2)
  978. ax.tick_params(axis='both', which='major', labelsize=8, length=1)
  979. ax.spines["right"].set_visible(False)
  980. ax.spines["top"].set_visible(False)
  981. ax.xaxis.set_ticks_position('bottom')
  982. ax.yaxis.set_ticks_position('left')
  983. ax.yaxis.grid(False)
  984. plt.ylim([0, 1.1])
  985. # plt.savefig('./drive/MyDrive/Colab Notebooks/figure/Lesion_performance_detection_' + "{:.2f}".format(this_cst) + '.pdf', dpi = 300)
  986. # %%
  987. acc_detect_raw = scipy.io.loadmat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/Exocos_RNN_lesion_acc_detection.mat')
  988. acc_detect = acc_detect_raw['data_mat']
  989. np.shape(acc_detect)
  990. clust_to_lesion = [None,5,2,4,1,3]
  991. cst_to_plot = [0.01, 0.05, 0.10, 0.20, 0.30,0.4, 0.5, 0.6, 0.7]
  992. for id_cst, this_cst in enumerate(cst_to_plot):
  993. ## Calculate the average and std
  994. if this_cst == 0.4:
  995. acc = acc_detect[id_cst]
  996. acc_mean = np.mean(acc, axis = 2).reshape((1, np.size(clust_to_lesion) * 2 )) # acc -> cluster * cond * block of 50
  997. acc_std = np.std(acc, axis = 2).reshape((1, np.size(clust_to_lesion) * 2 ))
  998. # Define labels, positions, bar heights and error bar heights
  999. labels = ['Intact', 'Visual', 'Sustain', 'Late', 'Reorient', 'Deactive']
  1000. acc_rearrange = np.array([acc[0,0,:],acc[0,1,:],acc[1,0,:],acc[1,1,:],acc[2,0,:],acc[2,1,:],acc[3,0,:],acc[3,1,:],acc[4,0,:],acc[4,1,:],acc[5,0,:],acc[5,1,:]])
  1001. np.shape(acc_rearrange.transpose())
  1002. print(np.mean(acc_rearrange,axis = 1))
  1003. np.savetxt("./drive/MyDrive/Colab Notebooks/figure/detection04_.csv", acc_rearrange.transpose(), delimiter=",")
  1004. # %%
  1005. # %% [markdown]
  1006. # #### Accuracy for discrimination task
  1007. # %%
  1008. ### find the accuracy of model for SEEN valid and invalid seperately, binary comparison
  1009. basicModel.destruct()
  1010. cst_to_plot = [0.01, 0.05, 0.10, 0.20, 0.30, 0.40,0.5,0.6,0.7]
  1011. acc_all = []
  1012. for i_cst, this_target_intensity in enumerate(cst_to_plot): # 0.02,0.05,0.06,0.08,0.10,0.15,0.2,0.3,0.40
  1013. print(this_target_intensity)
  1014. # Define probing target intensity
  1015. ExocosModel = ExogenousAttention(target_indensity= this_target_intensity, dt = dt, tau = tau, T = T, N_batch = N_batch, attention_gain = 1.5)
  1016. # order [5,2,4,1,3]
  1017. clust_to_lesion = [None,5,2,4,1,3]
  1018. acc = []
  1019. for id_n,this_clust in enumerate(clust_to_lesion):
  1020. # import trained model by importing its weights
  1021. load_network_params = network_params.copy()
  1022. load_network_params['load_weights_path'] = "./drive/MyDrive/Colab Notebooks/TrainedModelStates/ExocosTrainedModels__I150000_Target0p10_Gain1p5_summary.npz"
  1023. TrainedModel = Basic(load_network_params)
  1024. weights = TrainedModel.get_weights()
  1025. TrainedModel.destruct()
  1026. load_network_params = network_params.copy()
  1027. # get units index in this cluster
  1028. if this_clust is None:
  1029. unit_indices = None
  1030. else:
  1031. unit_indices = [index for index, element in enumerate(id_clust) if element == this_clust]
  1032. # modify weights in these units and reload a modified model
  1033. weights_mod = lesion_units(weights, unit_indices)
  1034. np.savez('./weights/modified_saved_weights.npz', **weights_mod)
  1035. load_network_params['load_weights_path'] = './weights/modified_saved_weights.npz'
  1036. ModifiedModel = Basic(load_network_params)
  1037. # assessing the accuracy of lesioned model
  1038. acc.append(test_model_acc_seen(ExocosModel, ModifiedModel))
  1039. # destruct model once used
  1040. ModifiedModel.destruct()
  1041. acc_all.append(acc)
  1042. ## save to Matlab format
  1043. acc_discrimination_struct = {"data_mat":acc_all,
  1044. "task": "discrimination",
  1045. "labels" : "valid and invalid"}
  1046. scipy.io.savemat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/Exocos_RNN_lesion_acc_discrimination.mat', acc_discrimination_struct)
  1047. # %%
  1048. acc_discri_raw = scipy.io.loadmat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/Exocos_RNN_lesion_acc_discrimination.mat')
  1049. acc_discri = acc_discri_raw['data_mat']
  1050. print(np.shape(acc_discri))
  1051. cst_to_plot = [0.01, 0.05, 0.10, 0.20, 0.30, 0.40,0.5,0.6,0.7]
  1052. for id_cst, this_cst in enumerate(cst_to_plot):
  1053. ## Calculate the average and std
  1054. acc = acc_discri[id_cst]
  1055. acc_mean = np.mean(acc, axis = 2).reshape((1, np.size(clust_to_lesion) * 2 )) # acc -> cluster * cond * block of 50
  1056. acc_std = np.std(acc, axis = 2).reshape((1, np.size(clust_to_lesion) * 2 ))
  1057. # Define labels, positions, bar heights and error bar heights
  1058. labels = ['Intact', 'Visual', 'Sustained', 'Late accum.', 'Reorient', 'Deactive']
  1059. label_pos = np.arange(np.size(clust_to_lesion)) + 1
  1060. x_pos = [(i+1-0.17,i+1+0.17) for i in range(len(clust_to_lesion))]
  1061. x_pos = np.array(x_pos).reshape((1, np.size(clust_to_lesion) * 2 ))[0]
  1062. CTEs = acc_mean[0]
  1063. error = acc_std[0]
  1064. # Build the plot
  1065. fig = plt.figure(figsize=(2.5,2.5))
  1066. ax = fig.add_axes([0.3,0.27, 0.6, 0.6])
  1067. ax.bar(x_pos, CTEs,
  1068. yerr=error,
  1069. align='center',
  1070. width=0.3,
  1071. alpha=0.9,
  1072. color = [(21/255,163/255,205/255), (221/255,102/255,155/255),(21/255,163/255,205/255), (221/255,102/255,155/255),
  1073. (21/255,163/255,205/255), (221/255,102/255,155/255),(21/255,163/255,205/255), (221/255,102/255,155/255),
  1074. (21/255,163/255,205/255), (221/255,102/255,155/255)],
  1075. ecolor='black',
  1076. capsize= 3)
  1077. text_font = 10
  1078. ax.set_xticks(label_pos)
  1079. ax.set_xticklabels(labels, rotation = 45)
  1080. plt.ylabel('Accuracy (%)', fontsize=text_font)
  1081. plt.title('target contrast: ' + "{:.2f}".format(this_cst), fontsize=text_font, y=1.05)
  1082. plt.locator_params(axis='y', nbins=2)
  1083. ax.tick_params(axis='both', which='major', labelsize=8, length=1)
  1084. ax.spines["right"].set_visible(False)
  1085. ax.spines["top"].set_visible(False)
  1086. ax.xaxis.set_ticks_position('bottom')
  1087. ax.yaxis.set_ticks_position('left')
  1088. ax.yaxis.grid(False)
  1089. plt.ylim([0, 1.1])
  1090. ###################################################################################
  1091. ## Statistical testing
  1092. for i_c in range(np.size(clust_to_lesion)):
  1093. s_p = stats.ttest_ind(acc[i_c][0], acc[i_c][1]).pvalue
  1094. multicorrection = 6 * 50
  1095. fsize = 12
  1096. if s_p < 0.001 / multicorrection :
  1097. mark_s = "*"
  1098. plt.text(i_c+1 , 1.02, mark_s, ha='center', va='bottom', fontsize = fsize)
  1099. elif s_p < 0.01 / multicorrection :
  1100. mark_s = "*"
  1101. plt.text(i_c+1 , 1.02, mark_s, ha='center', va='bottom', fontsize = fsize)
  1102. elif s_p < 0.05 / multicorrection :
  1103. mark_s = "*"
  1104. plt.text(i_c+1 , 1.02, mark_s, ha='center', va='bottom', fontsize = fsize)
  1105. ###################################################################################
  1106. plt.savefig('./drive/MyDrive/Colab Notebooks/figure/Lesion_performance_discrimination' + "{:.2f}".format(this_cst) + '.pdf', dpi = 300)
  1107. # %% [markdown]
  1108. # # 9 - Network structure analysis
  1109. # %% [markdown]
  1110. # ### Anatomical : connection weight
  1111. # %%
  1112. from matplotlib.colors import Normalize
  1113. import scipy.stats as stats
  1114. import scipy.io
  1115. def plot_weights(weights, title=""):
  1116. cmap = plt.set_cmap('RdBu_r')
  1117. img = plt.matshow(weights, norm=Normalize(vmin=-.5, vmax=.5))
  1118. plt.title(title)
  1119. plt.colorbar()
  1120. plt.xticks([8, 24, 28, 34, 36, 44, 47, 49, 50], ['Visual', 'Sustain_E','Sustain_I', 'Late_E','Late_I', 'Reorient_E','Reorient_I', 'Decreased_E','Decreased_I'], rotation=45)
  1121. plt.yticks([8, 24, 28, 34, 36, 44, 47, 49, 50], ['Visual', 'Sustain_E','Sustain_I', 'Late_E','Late_I', 'Reorient_E','Reorient_I', 'Decreased_E','Decreased_I'], rotation=0)
  1122. # %%
  1123. ## load a trained model
  1124. # basicModel.destruct()
  1125. load_network_params = network_params.copy()
  1126. load_network_params['load_weights_path'] = './drive/MyDrive/Colab Notebooks/TrainedModelStates/ExocosTrainedModels__I150000_' + 'Target0p10_Gain1p5_summary' + '.npz'
  1127. basicModel = Basic(load_network_params)
  1128. # %%
  1129. ## load clustering index for each unit
  1130. id_clust = scipy.io.loadmat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/clust_id_0p10_k5.mat')['id'][0].astype(np.float32)
  1131. id_clust[40:50] = id_clust[40:50] + 0.5 # to seperate inhibitory (+0.5) and excitatory
  1132. #clust_to_lesion = [5,2,4,1,3]
  1133. #labels = ['Visual', 'Sustain', 'Late', 'Reorient', 'Decreased']
  1134. # reorder clustering order as label order
  1135. id_clust[id_clust == 1] = 6
  1136. id_clust[id_clust == 5] = 1
  1137. id_clust[id_clust == 3] = 5
  1138. id_clust[id_clust == 4] = 3
  1139. id_clust[id_clust == 6] = 4
  1140. id_clust[id_clust == 1.5] = 6.5
  1141. id_clust[id_clust == 5.5] = 1.5
  1142. id_clust[id_clust == 3.5] = 5.5
  1143. id_clust[id_clust == 4.5] = 3.5
  1144. id_clust[id_clust == 6.5] = 4.5
  1145. # %%
  1146. weights = basicModel.get_weights()
  1147. plot_weights(weights['W_rec'])
  1148. # %%
  1149. def sort_corr_index(r, idx_sort):
  1150. nb_unit = np.shape(idx_sort)[0]
  1151. sorted_mat = np.zeros((nb_unit, nb_unit))
  1152. for i in range(nb_unit):
  1153. idx = idx_sort[i]
  1154. for j in range(nb_unit):
  1155. idx2 = idx_sort[j]
  1156. sorted_mat[i,j] = r[idx,idx2]
  1157. return sorted_mat
  1158. idx_sort = np.argsort(id_clust)
  1159. w_rec_sorted = sort_corr_index(weights['W_rec'], idx_sort)
  1160. plot_weights(w_rec_sorted)
  1161. plt.clim(-0.4,0.4)
  1162. # %%
  1163. cmap = plt.set_cmap('RdBu_r')
  1164. img = plt.matshow(w_rec_sorted[8:47,8:47], norm=Normalize(vmin=-.5, vmax=.5))
  1165. plt.colorbar()
  1166. FP_tick = np.array([24, 28, 34, 36, 44, 47]) - 8
  1167. plt.xticks(FP_tick, ['Sustain_E','Sustain_I', 'Late_E','Late_I', 'Reorient_E','Reorient_I'], rotation=45)
  1168. plt.yticks(FP_tick, ['Sustain_E','Sustain_I', 'Late_E','Late_I', 'Reorient_E','Reorient_I'], rotation=0)
  1169. plt.clim(-0.4,0.4)
  1170. plt.savefig('./drive/MyDrive/Colab Notebooks/figure/RNN_E_I_recurrent_weight.pdf', dpi = 300)
  1171. # %%
  1172. # !pip install statsmodels
  1173. import statsmodels.stats.multitest as mlt
  1174. # %%
  1175. ## visualization seperate plot inhibitory and excitatory figures
  1176. # plot excitatory
  1177. w_rec_exci = w_rec_sorted.copy()
  1178. # threshold_value = w_rec_exci[ w_rec_exci > 0].mean() + 3* np.std(w_rec_exci[ w_rec_exci > 0])
  1179. threshold_value = w_rec_exci[ w_rec_exci > 0].mean()
  1180. # w_rec_exci[ w_rec_exci < threshold_value] = 0
  1181. plot_weights(w_rec_exci)
  1182. nb_unit_clust = [8, 16, 4, 6, 2, 8, 3, 2, 1] # nb of unit in each cluster
  1183. nb_clust = len(nb_unit_clust)
  1184. Exci_weight = np.zeros((nb_clust,nb_clust))
  1185. Exci_weight_p = np.zeros((nb_clust,nb_clust))
  1186. idx_x_start = 0 # the row
  1187. idx_x_end = 0 # the row
  1188. idx_y_start = 0 # the columne
  1189. idx_y_end = 0 # the columne
  1190. for i, nb_unit in enumerate(nb_unit_clust):
  1191. idx_x_start = idx_x_start
  1192. idx_x_end = idx_x_start + nb_unit
  1193. for j in range(len(nb_unit_clust)):
  1194. idx_y_start = idx_y_start
  1195. idx_y_end = idx_y_start + nb_unit_clust[j]
  1196. Exci_tmp = w_rec_exci[idx_x_start:idx_x_end, idx_y_start:idx_y_end]
  1197. Exci_weight_p[i,j] = stats.ttest_1samp(a= Exci_tmp.flatten(), popmean= threshold_value, alternative = 'greater').pvalue # perform one sample t-test
  1198. Exci_weight[i,j] = Exci_tmp.mean()
  1199. idx_y_start = idx_y_start + nb_unit_clust[j]
  1200. idx_y_start = 0
  1201. idx_x_start = idx_x_start + nb_unit
  1202. ## multicorrection with holm-bofferoni correction
  1203. # https://www.statsmodels.org/dev/generated/statsmodels.stats.multitest.multipletests.html
  1204. Exci_weight_FP = Exci_weight[1:7,1:7]
  1205. Exci_weight_FP_p = Exci_weight_p[1:7,1:7]
  1206. [rej, pvals_corrected, alphacSidak,alphacBonf] = mlt.multipletests(Exci_weight_FP_p, alpha=0.05, method='holm-sidak')
  1207. Exci_weight_FP_copy = Exci_weight_FP.copy()
  1208. Exci_weight_FP[Exci_weight_FP_p > alphacBonf] = 0
  1209. Exci_weight_FP[Exci_weight_FP<0] =0
  1210. cmap = plt.set_cmap('RdBu_r')
  1211. img = plt.matshow(Exci_weight_FP, norm=Normalize(vmin=-.2, vmax=.2))
  1212. plt.colorbar()
  1213. plt.clim(-0.4,0.4)
  1214. xlab = np.arange(6)
  1215. plt.xticks(xlab,['S_E','S_I', 'L_E','L_I', 'R_E','R_I'], rotation = 45)
  1216. plt.yticks(xlab,['Sustain_E','Sustain_I', 'Late_E','Late_I', 'Reorient_E','Reorient_I'])
  1217. # %%
  1218. ## use 9*9 as multicorrection test
  1219. [rej, pvals_corrected, alphacSidak,alphacBonf] = mlt.multipletests(Exci_weight_p, alpha=0.05, method='holm-sidak')
  1220. Exci_weight_copy = Exci_weight.copy()
  1221. Exci_weight[Exci_weight_p > alphacBonf] = 0
  1222. Exci_weight[Exci_weight<0] =0
  1223. cmap = plt.set_cmap('RdBu_r')
  1224. img = plt.matshow(Exci_weight, norm=Normalize(vmin=-.2, vmax=.2))
  1225. plt.colorbar()
  1226. plt.clim(-0.4,0.4)
  1227. xlab = np.arange(9)
  1228. plt.xticks(xlab,['Visual', 'S_E','S_I', 'L_E','L_I', 'R_E','R_I', 'D_E','D_I'], rotation = 45)
  1229. plt.yticks(xlab,['Visual', 'Sustain_E','Sustain_I', 'Late_E','Late_I', 'Reorient_E','Reorient_I', 'Decreased_E','Decreased_I'])
  1230. # %% [markdown]
  1231. # %%
  1232. Exci_weight_FP = Exci_weight[1:7,1:7]
  1233. cmap = plt.set_cmap('RdBu_r')
  1234. img = plt.matshow(Exci_weight_FP, norm=Normalize(vmin=-.2, vmax=.2))
  1235. plt.colorbar()
  1236. xlab = np.arange(6)
  1237. plt.xticks(xlab,['S_E','S_I', 'L_E','L_I', 'R_E','R_I'], rotation = 45)
  1238. plt.yticks(xlab,['Sustain_E','Sustain_I', 'Late_E','Late_I', 'Reorient_E','Reorient_I'])
  1239. # %%
  1240. Exci_weight_FP
  1241. # %%
  1242. ## visualization seperate plot inhibitory and excitatory figures
  1243. # plot inhibitory
  1244. w_rec_inhi = w_rec_sorted.copy()
  1245. threshold_value = w_rec_inhi[ w_rec_inhi < 0].mean()
  1246. w_rec_inhi[w_rec_inhi > 0 ] = 0
  1247. nb_unit_clust = [8, 16, 4, 6, 2, 8, 3, 2, 1] # nb of unit in each cluster
  1248. nb_clust = len(nb_unit_clust)
  1249. Inhi_weight = np.zeros((nb_clust,nb_clust))
  1250. Inhi_weight_p = np.zeros((nb_clust,nb_clust))
  1251. idx_x_start = 0 # the row
  1252. idx_x_end = 0 # the row
  1253. idx_y_start = 0 # the columne
  1254. idx_y_end = 0 # the columne
  1255. for i, nb_unit in enumerate(nb_unit_clust):
  1256. idx_x_start = idx_x_start
  1257. idx_x_end = idx_x_start + nb_unit
  1258. for j in range(len(nb_unit_clust)):
  1259. idx_y_start = idx_y_start
  1260. idx_y_end = idx_y_start + nb_unit_clust[j]
  1261. Inhi_tmp = w_rec_inhi[idx_x_start:idx_x_end, idx_y_start:idx_y_end]
  1262. Inhi_weight_p[i,j] = stats.ttest_1samp(a= Inhi_tmp.flatten(), popmean= threshold_value, alternative = 'less').pvalue # perform one sample t-test
  1263. Inhi_weight[i,j] = Inhi_tmp.mean()
  1264. idx_y_start = idx_y_start + nb_unit_clust[j]
  1265. idx_y_start = 0
  1266. idx_x_start = idx_x_start + nb_unit
  1267. ## multicorrection with holm-bofferoni correction
  1268. # https://www.statsmodels.org/dev/generated/statsmodels.stats.multitest.multipletests.html
  1269. [rej, pvals_corrected, alphacSidak,alphacBonf] = mlt.multipletests(Inhi_weight_p, alpha=0.05, method='hs')
  1270. Inhi_weight[Inhi_weight_p > alphacBonf] = 0
  1271. print(alphacBonf)
  1272. Inhi_weight[Inhi_weight>0] =0
  1273. cmap = plt.set_cmap('RdBu_r')
  1274. img = plt.matshow(Inhi_weight, norm=Normalize(vmin=-.2, vmax=.2))
  1275. plt.colorbar()
  1276. xlab = np.arange(9)
  1277. plt.xticks(xlab,['Visual', 'S_E','S_I', 'L_E','L_I', 'R_E','R_I', 'D_E','D_I'], rotation = 45)
  1278. plt.yticks(xlab,['Visual', 'Sustain_E','Sustain_I', 'Late_E','Late_I', 'Reorient_E','Reorient_I', 'Decreased_E','Decreased_I'])
  1279. # %%
  1280. Inhi_weight
  1281. # %%
  1282. ## statistical test of input and output connections
  1283. W_in_sorted = weights['W_in'][idx_sort]
  1284. W_out_sorted = np.transpose(weights['W_out'])[idx_sort]
  1285. # %%
  1286. fig = plt.figure(figsize=(4, 3))
  1287. cmap = plt.set_cmap('RdBu_r')
  1288. img = plt.matshow(W_in_sorted[8:47], norm=Normalize(vmin=-.5, vmax=.5))
  1289. plt.colorbar()
  1290. plt.yticks(FP_tick, ['Sustain_E','Sustain_I', 'Late_E','Late_I', 'Reorient_E','Reorient_I'], rotation=0)
  1291. plt.clim(-0.5,0.5)
  1292. plt.savefig('./drive/MyDrive/Colab Notebooks/figure/RNN_E_I_input_weight.pdf', dpi = 300)
  1293. W_in_p = np.zeros(9)
  1294. W_in_mean = np.zeros(9)
  1295. idx_start = 0
  1296. for i, nb_u in enumerate(nb_unit_clust):
  1297. W_in_p[i] = stats.ttest_1samp(a= W_in_sorted[idx_start:idx_start+nb_u].flatten(), popmean= 0).pvalue
  1298. W_in_mean[i] = W_in_sorted[idx_start:idx_start+nb_u].mean()
  1299. idx_start = idx_start + nb_u
  1300. [rej, pvals_corrected_in, alphacSidak,alphacBonf_in] = mlt.multipletests(W_in_p, alpha=0.05, method='holm-sidak')
  1301. W_in_mean[pvals_corrected_in > 0.05] = 0
  1302. W_in_mean
  1303. # %%
  1304. cmap = plt.set_cmap('RdBu_r')
  1305. img = plt.matshow(W_out_sorted[8:47], norm=Normalize(vmin=-.5, vmax=.5))
  1306. plt.colorbar()
  1307. plt.yticks(FP_tick, ['Sustain_E','Sustain_I', 'Late_E','Late_I', 'Reorient_E','Reorient_I'], rotation=0)
  1308. plt.clim(-0.5,0.5)
  1309. plt.savefig('./drive/MyDrive/Colab Notebooks/figure/RNN_E_I_output_weight.pdf', dpi = 300)
  1310. W_out_p = np.zeros(9)
  1311. W_out_mean = np.zeros(9)
  1312. idx_start = 0
  1313. for i, nb_u in enumerate(nb_unit_clust):
  1314. W_out_p[i] = stats.ttest_1samp(a= W_out_sorted[idx_start:idx_start+nb_u].flatten(), popmean= 0).pvalue
  1315. W_out_mean[i] = W_out_sorted[idx_start:idx_start+nb_u].mean()
  1316. idx_start = idx_start + nb_u
  1317. # [rej, pvals_corrected_out, alphacSidak,alphacBonf_out] = mlt.multipletests(W_out_p, alpha=0.05, method='holm-sidak')
  1318. W_out_mean[W_out_p > 0.05] = 0
  1319. W_out_mean[1:7]
  1320. # %%
  1321. W_out_p
  1322. # %% [markdown]
  1323. # ## Functional : global ignition of response
  1324. # %%
  1325. dt = 10 # The simulation timestep.
  1326. tau = 100 # The intrinsic time constant of neural state decay.
  1327. T = 1600 # The trial length.
  1328. N_batch = 50 # The number of trials per training update.
  1329. N_rec = 50 # The number of recurrent units in the network.
  1330. name = 'ExocosModel' # Unique name used to determine variable scope for internal use.
  1331. ## load a trained model
  1332. # TrainedModel.destruct()
  1333. load_network_params = network_params.copy()
  1334. load_network_params['load_weights_path'] = './drive/MyDrive/Colab Notebooks/TrainedModelStates/ExocosTrainedModels__I150000_' + 'Target0p10_Gain1p5_summary' + '.npz'
  1335. TrainedModel = Basic(load_network_params)
  1336. ## load cluster id
  1337. id_clust = scipy.io.loadmat('./drive/MyDrive/Colab Notebooks/TrainedModelStates/clust_id_0p10_k5.mat')['id'][0]
  1338. # %%
  1339. basicModel.destruct()
  1340. # %%
  1341. clust_ignition = [5,2,4,1]
  1342. labels = ['Visual','Sustain', 'Late', 'Reorient']
  1343. target_indensities = np.arange(0.00,0.12,0.01)
  1344. V_contrast_peak_raw = []
  1345. Inv_contrast_peak_raw = []
  1346. Abs_contrast_peak_raw = []
  1347. for this_target_indensity in target_indensities:
  1348. print("computing: " + "{:.2f}".format(this_target_indensity))
  1349. ExocosModel = ExogenousAttention(dt = dt, tau = tau, T = T, N_batch = N_batch, target_indensity = this_target_indensity) # Initialize the task object
  1350. ### Cluster activation
  1351. V_contrast_peak_batch = []
  1352. Inv_contrast_peak_batch = []
  1353. Abs_contrast_peak_batch = []
  1354. for i_batch in range(20):# (1,50):
  1355. x,y,m, trial_params = ExocosModel.get_trial_batch()
  1356. output, state_var = TrainedModel.test(x)
  1357. # find index for each trial condition
  1358. V_idx = [];
  1359. Inv_idx = [];
  1360. Abs_idx = [];
  1361. for i in range(50):
  1362. if trial_params[i]['detection'] == 0:
  1363. Abs_idx.append(i)
  1364. elif trial_params[i]['cue_position'] == trial_params[i]['target_position']:
  1365. V_idx.append(i)
  1366. else:
  1367. Inv_idx.append(i)
  1368. V_units_peak = np.mean(state_var[V_idx,60:100,:], axis=1) #-> V_units_peak: trial * 50 units
  1369. Inv_units_peak = np.mean(state_var[Inv_idx,60:100,:], axis=1)
  1370. Abs_units_peak = np.mean(state_var[Abs_idx,60:100,:], axis=1)
  1371. # find index for each cluster
  1372. V_units_peak_cluster = []
  1373. Inv_units_peak_cluster = []
  1374. Abs_units_peak_cluster = []
  1375. for this_cluster in clust_ignition:
  1376. unit_indices = [index for index, element in enumerate(id_clust) if element == this_cluster]
  1377. V_units_peak_cluster.append(np.mean(V_units_peak[:,unit_indices])) # -> trial one value for each cluster n*1
  1378. Inv_units_peak_cluster.append(np.mean(Inv_units_peak[:,unit_indices])) # -> trial one value for each cluster n*1
  1379. Abs_units_peak_cluster.append(np.mean(Abs_units_peak[:,unit_indices])) # -> trial one value for each cluster n*1
  1380. V_contrast_peak_batch.append(V_units_peak_cluster)
  1381. Inv_contrast_peak_batch.append(Inv_units_peak_cluster)
  1382. Abs_contrast_peak_batch.append(Abs_units_peak_cluster)
  1383. V_contrast_peak_raw.append(V_contrast_peak_batch)
  1384. Inv_contrast_peak_raw.append(Inv_contrast_peak_batch)
  1385. Abs_contrast_peak_raw.append(Abs_contrast_peak_batch)
  1386. V_contrast_peak = np.mean(V_contrast_peak_raw, axis = 1)
  1387. Inv_contrast_peak = np.mean(Inv_contrast_peak_raw, axis = 1)
  1388. Abs_contrast_peak = np.mean(Abs_contrast_peak_raw, axis = 1)
  1389. # %%
  1390. data_v_peak = V_contrast_peak.copy()
  1391. data_inv_peak = Inv_contrast_peak.copy()
  1392. data_abs_peak = Abs_contrast_peak.copy()
  1393. v = (np.array(data_v_peak) - np.mean(data_abs_peak, axis= 0))
  1394. inv = (np.array(data_inv_peak) - np.mean(data_abs_peak, axis= 0))
  1395. fig = plt.figure(figsize=(4, 6))
  1396. ax = fig.add_axes([0.3,0.2, 0.6, 0.6])
  1397. colors = ['y','C1','r','b']
  1398. labels = ['Visual v','Sustain V', 'Late V', 'Reorient V','Visual inv', 'Sustain Inv', 'Late Inv','Reorient Inv']
  1399. import statsmodels.stats.multitest as mlt
  1400. for i in range(4):
  1401. ax.plot(v[:,i], '-', color = colors[i], label = labels[i], linewidth=2)
  1402. ax.plot(inv[:,i], '--', color = colors[i], label = labels[i], linewidth=2)
  1403. ###################################################################################
  1404. ## Statistical testing
  1405. for i_c in range(np.shape(V_contrast_peak)[0]):
  1406. s_p = stats.ttest_ind(np.transpose(V_contrast_peak_raw[i_c])[i], np.transpose(Inv_contrast_peak_raw[i_c])[i]).pvalue
  1407. [rej, pvals_corrected, alphacSidak,alphacBonf] = mlt.multipletests(s_p, alpha=0.05, method='holm-sidak')
  1408. fsize = 12
  1409. if pvals_corrected < 0.05 :
  1410. mark_s = "*"
  1411. plt.text(i_c+1 , 0.3 + 0.01 * i, mark_s, ha='center', va='bottom', fontsize = fsize, color = colors[i])
  1412. ###################################################################################
  1413. text_font = 10
  1414. plt.xlabel('Target contrast(a.u.)', fontsize=text_font)
  1415. plt.ylabel('Activation(a.u.)', fontsize=text_font)
  1416. plt.locator_params(axis='y', nbins=2)
  1417. ax.tick_params(axis='both', which='major', labelsize=8, length=1)
  1418. ax.spines["right"].set_visible(False)
  1419. ax.spines["top"].set_visible(False)
  1420. ax.xaxis.set_ticks_position('bottom')
  1421. ax.yaxis.set_ticks_position('left')
  1422. plt.legend( ['Visual V','Visual Inv','Sustain V', 'Sustain Inv', 'Late. Inv', 'Late. V','Reorient. V','Reorient. Inv'])
  1423. # plt.savefig('./drive/MyDrive/Colab Notebooks/figure/RNN_cluster_activation_contrast.pdf', dpi = 300)
  1424. # %%
  1425. data_v_peak = V_contrast_peak.copy()
  1426. data_inv_peak = Inv_contrast_peak.copy()
  1427. data_abs_peak = Abs_contrast_peak.copy()
  1428. v = (np.array(data_v_peak) - np.mean(data_abs_peak, axis= 0))
  1429. inv = (np.array(data_inv_peak) - np.mean(data_abs_peak, axis= 0))
  1430. np.savetxt("./drive/MyDrive/Colab Notebooks/figure/fig4e_v.csv", v, delimiter=",")
  1431. np.savetxt("./drive/MyDrive/Colab Notebooks/figure/fig4e_iv.csv", inv, delimiter=",")
  1432. # %% [markdown]
  1433. # # 10 -NeuroData PCA visualization
  1434. # %%
  1435. ls
  1436. # %%
  1437. SEEG_Raw = []
  1438. import scipy.io
  1439. SEEG_Raw = scipy.io.loadmat('./drive/MyDrive/Colab Notebooks/sEEGdata/HFBB_allpp_Elec_time_cond_norm.mat')
  1440. clust_id_raw = scipy.io.loadmat('./drive/MyDrive/Colab Notebooks/sEEGdata/clust_id_k10.mat')
  1441. clust_id = clust_id_raw['id'][0]
  1442. print(np.shape(clust_id))
  1443. # %%
  1444. Elec_time_cond = SEEG_Raw['Elec_time_cond']
  1445. print(np.shape(Elec_time_cond))
  1446. Cond_time_elec = np.transpose(Elec_time_cond, (2, 1, 0))
  1447. print(np.shape(Cond_time_elec))
  1448. # Label_seeg_all = [1,0,1,0,1,0,1,0,] # seen vs unseen
  1449. Label_seeg_all = [1,1,0,0,1,1,0,0,] # valid vs invalid
  1450. # %% [markdown]
  1451. # ### clustering result visualization
  1452. # %%
  1453. Elec_features = np.reshape(Elec_time_cond, (727,-1))
  1454. np.shape(Elec_features)
  1455. # %%
  1456. fig = plt.figure(figsize=(8, 4))
  1457. X = Elec_features
  1458. # X = np.mean(Elec_time_cond, axis = 2)
  1459. y = clust_id
  1460. #model = PCA(n_components=2)
  1461. model = TSNE(n_components=2, random_state=0, init='pca',
  1462. verbose=1, metric = 'cityblock', method='exact',
  1463. learning_rate=100, perplexity=30)
  1464. X_r = model.fit_transform(X)
  1465. colors = [(21/255,163/255,205/255), (221/255,102/255,155/255),'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w']
  1466. lw = 2
  1467. # %%
  1468. fig = plt.figure()
  1469. clst_to_plot = [10,8,9,1,5]
  1470. for color, i in zip(colors, clst_to_plot):
  1471. plt.scatter(X_r[y == i, 0], X_r[y == i, 1], s = 10, color=color, marker= 'o', lw=lw)
  1472. print(i)
  1473. plt.xlabel('t-SNE component 1', fontsize=10)
  1474. plt.ylabel('t-SNE component 2', fontsize=10)
  1475. plt.locator_params(axis='y', nbins=2)
  1476. # ax.yaxis.set_ticks_position('left')
  1477. #ax.set_xticks([])
  1478. #ax.set_yticks([])
  1479. #plt.xlim(-1000, 200)
  1480. #plt.ylim(-200, 150)
  1481. plt.xlim(-900, 1500)
  1482. plt.ylim(-200, 100)
  1483. plt.legend(['cluster 1','cluster 2','cluster 3','cluster 4','cluster 5'])
  1484. # ax.axis('off')
  1485. plt.savefig('./drive/MyDrive/Colab Notebooks/sEEGdata/t_sne_5_neural clusters.pdf',dpi = 300)
  1486. # %% [markdown]
  1487. # ### pca with all electrode
  1488. # %%
  1489. fig = plt.figure(figsize=(8, 4))
  1490. # Calculate mean or variance
  1491. X = np.var(Cond_time_elec, axis = 2)
  1492. y = np.array(Label_seeg_all)
  1493. model = PCA(n_components=2)
  1494. X_r = model.fit_transform(X)
  1495. # Percentage of variance explained for each components
  1496. print('explained variance ratio (first two components): %s' % str(model.explained_variance_ratio_))
  1497. target_names = ['Valid', 'Invalid']
  1498. colors = [(254/255,157/255,30/255), (21/255,163/255,205/255)]
  1499. lw = 2
  1500. ax = fig.add_axes([0.2, 0.2, 0.3, 0.5])
  1501. # seen
  1502. s_row = [0,2,4,6]
  1503. X_r_s = X_r[s_row , : ]
  1504. for color, i, target_name in zip(colors, [1, 0], target_names):
  1505. plt.scatter(X_r_s[y[s_row] == i, 0], X_r_s[y[s_row] == i, 1], s = 80, color=color, marker= 'v', lw=lw,
  1506. label=target_name)
  1507. # unseen
  1508. us_row = [1,3,5,7]
  1509. X_r_us = X_r[us_row , : ]
  1510. for color, i, target_name in zip(colors, [1, 0], target_names):
  1511. plt.scatter(X_r_us[y[us_row] == i, 0], X_r_us[y[us_row] == i, 1], s = 80, color=color, marker= 'o', lw=lw, facecolors='none',
  1512. label=target_name)
  1513. plt.legend(['SV','UV','SI','UI'],loc='best', shadow=False, scatterpoints=1, fontsize = 12, frameon=False, bbox_to_anchor=(0.3, 1.2, 1., .1))
  1514. plt.xlim(-10000, 30000)
  1515. plt.ylim(-3000, 8000)
  1516. plt.xlabel('PC1', fontsize=10)
  1517. plt.ylabel('PC2', fontsize=10)
  1518. plt.locator_params(axis='y', nbins=2)
  1519. ax.tick_params(axis='both', which='major', labelsize=8, length=1)
  1520. ax.spines["right"].set_visible(False)
  1521. ax.spines["top"].set_visible(False)
  1522. ax.xaxis.set_ticks_position('bottom')
  1523. ax.yaxis.set_ticks_position('left')
  1524. ax.xaxis.set_visible(False)
  1525. ax.xaxis.set_visible(False)
  1526. # ax.axis('off')
  1527. # plt.savefig('./drive/MyDrive/Colab Notebooks/figure/pca.png',dpi = 300)
  1528. # %%
  1529. fig = plt.figure(figsize=(8, 4))
  1530. # Calculate mean or variance
  1531. X = np.var(Cond_time_elec, axis = 2)
  1532. y = np.array(Label_seeg_all)
  1533. model = TSNE(n_components=2, random_state=0, init='pca',
  1534. verbose=1, method='exact',
  1535. learning_rate=100, perplexity=30)
  1536. X_r = model.fit_transform(X)
  1537. # Percentage of variance explained for each components
  1538. target_names = ['Valid', 'Invalid']
  1539. colors = [(21/255,163/255,205/255), (221/255,102/255,155/255)]
  1540. lw = 2
  1541. ax = fig.add_axes([0.2, 0.2, 0.3, 0.5])
  1542. # seen
  1543. s_row = [0,2,4,6]
  1544. X_r_s = X_r[s_row , : ]
  1545. for color, i, target_name in zip(colors, [1, 0], target_names):
  1546. plt.scatter(X_r_s[y[s_row] == i, 0], X_r_s[y[s_row] == i, 1], s = 80, color=color, marker= 'o', lw=lw,
  1547. label=target_name)
  1548. # unseen
  1549. us_row = [1,3,5,7]
  1550. X_r_us = X_r[us_row , : ]
  1551. for color, i, target_name in zip(colors, [1, 0], target_names):
  1552. plt.scatter(X_r_us[y[us_row] == i, 0], X_r_us[y[us_row] == i, 1], s = 80, color=color, marker= 'o', lw=lw, facecolors='none',
  1553. label=target_name)
  1554. plt.legend(['S V','S Iv','Us V','Us Iv'],loc='best', shadow=False, scatterpoints=1, fontsize = 10, frameon=False, bbox_to_anchor=(0.3, 0.9, 1., .1))
  1555. plt.xlabel('PC1', fontsize=10)
  1556. plt.ylabel('PC2', fontsize=10)
  1557. plt.locator_params(axis='y', nbins=2)
  1558. ax.tick_params(axis='both', which='major', labelsize=8, length=1)
  1559. ax.spines["right"].set_visible(False)
  1560. ax.spines["top"].set_visible(False)
  1561. ax.xaxis.set_ticks_position('bottom')
  1562. ax.yaxis.set_ticks_position('left')
  1563. ax.set_xticks([])
  1564. ax.set_yticks([])
  1565. plt.xlim(-20000, 30000)
  1566. plt.ylim(-7000, 8000)
  1567. # ax.axis('off')
  1568. plt.savefig('./drive/MyDrive/Colab Notebooks/sEEGdata/all_t_sne.pdf',dpi = 300)
  1569. # %% [markdown]
  1570. # ### Dynamic trajectory
  1571. # %%
  1572. Label_seeg_all = [0,2,1,3,0,2,1,3]
  1573. fig = plt.figure(figsize=(5,5))
  1574. target_names = ['seen valid','seen invalid','unseen valid','unseen invalid']
  1575. count = 0
  1576. markers = []
  1577. for i, cond in enumerate(target_names):
  1578. X = np.mean(Cond_time_elec[:,40:130,:], axis = 2) # var or mean
  1579. y = np.array(Label_seeg_all)
  1580. X_i = X[y == i]
  1581. # calculate PCA
  1582. model = TSNE(n_components=2, random_state=0, init='pca',
  1583. verbose=1, method='exact',
  1584. learning_rate=100, perplexity=30)
  1585. X_r = model.fit_transform(X_i.T)
  1586. #ax = fig.add_axes([0.2, 0.2, 0.4, 0.4])
  1587. ax = plt.subplot(2,2,count+1)
  1588. count+=1
  1589. c = np.array(range(X_r.shape[0]))
  1590. s = np.ones(X_r.shape[0]) * 10
  1591. s[10] = 100;
  1592. s[40] = 100;
  1593. cmap = plt.set_cmap('hot')
  1594. plt.scatter(X_r[:,0],X_r[:,1],s = s, c = c,marker = 'o',lw=lw, facecolors= 'none' )
  1595. #plt.xlim([-400,400])
  1596. #plt.ylim([-400,400])
  1597. plt.xlim([-10,10])
  1598. plt.ylim([-10,10])
  1599. plt.title(cond)
  1600. ax.axis('off')
  1601. plt.savefig('./drive/MyDrive/Colab Notebooks/sEEGdata/all_dynamic_mean.pdf',dpi = 300)
  1602. # %%
  1603. fig, ax = plt.subplots(figsize=(3.5,2))
  1604. cmap = plt.set_cmap('hot')
  1605. cax = plt.scatter(X_r[:,0],X_r[:,1],s = s, c = c,marker = 'o',lw=lw, facecolors= 'none' )
  1606. cbar = fig.colorbar(cax, ticks = [10, 40],aspect=10)
  1607. cbar.ax.set_yticklabels(['Cue', 'Target']) # vertically oriented colorbar
  1608. plt.savefig('./drive/MyDrive/Colab Notebooks/sEEGdata/all_colorbar.png',dpi = 300)
  1609. # %% [markdown]
  1610. # ### Dynamic trajectory -cluster
  1611. # %%
  1612. clust_id_raw = scipy.io.loadmat('./drive/MyDrive/Colab Notebooks/sEEGdata/clust_id_k10.mat')
  1613. clust_id = clust_id_raw['id'][0]
  1614. # %%
  1615. Label_seeg_all = [0,2,1,3,0,2,1,3]
  1616. clust_to_plots = [10,8,9,1,5]
  1617. for idx, cst in enumerate(clust_to_plots):
  1618. fig = plt.figure(figsize=(5,5))
  1619. target_names = ['seen valid','seen invalid','unseen valid','unseen invalid']
  1620. count = 0
  1621. markers = []
  1622. for i, cond in enumerate(target_names):
  1623. y = np.array(Label_seeg_all)
  1624. X_i = Cond_time_elec[y == i]
  1625. X_i_avg = np.mean(X_i[:,40:130, clust_id == cst], axis = 2) # average across elects, then use conditions as features
  1626. # calculate PCA
  1627. model = TSNE(n_components=2, random_state=0, init='pca',
  1628. verbose=0, method='exact',
  1629. learning_rate=100, perplexity=30)
  1630. X_r = model.fit_transform(X_i_avg.T)
  1631. #ax = fig.add_axes([0.2, 0.2, 0.4, 0.4])
  1632. ax = plt.subplot(2,2,count+1)
  1633. count+=1
  1634. c = np.array(range(X_r.shape[0]))
  1635. s = np.ones(X_r.shape[0]) * 10
  1636. s[10] = 100;
  1637. s[40] = 100;
  1638. cmap = plt.set_cmap('hot')
  1639. plt.scatter(X_r[:,0],X_r[:,1], s = s, c = c,marker = 'o',lw=lw, facecolors= 'none' )
  1640. #plt.xlim([-600,600])
  1641. #plt.ylim([-600,600])
  1642. plt.title(cond)
  1643. plt.xlim([-8,8])
  1644. plt.ylim([-8,8])
  1645. ax.axis('off')
  1646. plt.savefig('./drive/MyDrive/Colab Notebooks/sEEGdata/clust_dynamic_' + str(cst) + '.pdf',dpi = 300)

Exocos_attention_conscious_report.ipynb at commit d6ae07f, no license · at the source

Overview

Authors: Silvana Lozito1,2,3,4, Stefano Lasaponara1,3, Jianghao Liu2,5, Vincent Navarro6, Katia Lehongre7, Valerio Frazzini6, Tal Seidel Malkinson8, Fabrizio Doricchi1,3, Paolo Bartolomeo2
  1. Department of Psychology, “Sapienza” University of Rome, Via dei Marsi 78, 00185 Rome, Italy
  2. Sorbonne Université, Paris Brain Institute - ICM, Inserm, CNRS, AP-HP, Hôpital de la Pitié-Salpêtrière, 47 Bd de l'Hôpital, 75013 Paris, France
  3. IRCCS Fondazione Santa Lucia, Via Ardeatina 306/354, 00179 Rome, Italy
  4. PhD Programme in Behavioural Neuroscience, “Sapienza” University of Rome, Via dei Marsi 78, 00185 Rome, Italy
  5. Dassault Systèmes, 10 Rue Marcel Dassault, 78140 Vélizy-Villacoublay, France
  6. Epilepsy Unit, AP-HP, Piti Salpêtrière Hospital, 47 Bd de l'Hôpital, 75013 Paris, France
  7. CENIR - Centre de Neuro-Imagerie de Recherche, Paris Brain Institute, ICM, Hôpital de la Pitié-Salpêtrière, 47 Bd de l'Hôpital, 75013 Paris, France
  8. Université de Lorraine, CNRS, IMoPA, 9 Avenue de la Forêt de Haye, 54000 Nancy, France
Journal: Neuroscience of consciousness, volume 2026, issue 1, article niag011
Dates: received 17 June 2025; accepted 12 March 2026; published online 8 April 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1093/nc/niag011 · PMID 41969663 · PMCID PMC13069880 · OpenAlex W7153557887
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: EEG (modality), human (organism), cognitive (subfield)
Methods: Spectral & time-frequency, Connectivity, Statistics, Machine learning, Smoothing, state filtering, decompositions, Preprocessing, Evoked potentials, Physiology & signal measures
Keywords: consciousness, EEG, ERPs, intracerebral electrodes, P300, attention
Topic: Neural and Behavioral Psychology Studies (Cognitive Neuroscience, Neuroscience), according to OpenAlex
Funding: Italian National Recovery and Resilience Plan (B83C22003650006); PRIN 2022 (2022WPY4L3); Italian Ministry of Research and Education; Agence Nationale de la Recherche (ANR-16-CE37-0005, ANR-10-IAIHU-06); Fondation pour la Recherche sur les AVC (FR-AVC-017)
Citations: cited by 1 paper (Europe PMC); 26 references in the paper

Abstract

A recent study using intracerebral electroencephalography (EEG) recordings in human patients has documented the electrophysiological correlates of conscious reporting of near-threshold visual targets that followed supra-threshold peripheral spatial cues. Here, we aimed to bridge these intracerebral EEG events with corresponding surface recording, differentiating between conscious and nonconscious processing. We analysed the surface EEG of 10 patients from the intracerebral study. Due to a limited number of surface derivations, we pooled trials across participants to create a virtual participant for both surface and intracerebral analyses. Event-related potential (ERP) analysis revealed a significant positive deflection for Seen compared to Unseen targets in the 350–500 ms post-target window at frontal sites, consistent with a P3b component associated with conscious report. Time–frequency analysis revealed spectral dynamics associated with conscious report, including pretarget beta/gamma power modulations at frontal electrodes and post-target increased oscillatory activity at occipital sites. Trajectory k-means clustering of intracerebral data enabled us to identify two key patterns of post-target activity closely corresponding to the clusters from the original study: a Visual cluster exhibiting early (120–340 ms), transient responses, and an Accumulation cluster demonstrating gradual activity buildup (230–490 ms). Ridge regression analysis revealed that, compared to the Visual cluster, the Accumulation cluster contributed more to the prediction of report-related ERPs at the scalp level. These findings offer insights into bridging the gap between intracerebral recordings and surface EEG correlates of conscious report. They also highlight the greater contribution of late integrative mechanisms, compared to early sensory processes, in the conscious experience of behaviourally relevant targets.

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

Repositories

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

jianghao-liu/attentionconscious-report

License: none: the authors keep all their rights
State: the link is dead, verified on 29 September 2026
Evidence: found in the paper
Software Heritage: not archived
Found in: “Code availability”
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Availability: 1 check, the latest on 29 September 2026: the link is dead
  • 29 September 2026: the link is dead

Zenodo 8113973

License: other-open
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Size: 1 file
Software Heritage: not checked
Found in: “Code availability”
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: Matplotlib (1 file), NumPy (1 file), scikit-learn (1 file), SciPy (1 file), statsmodels (1 file), TensorFlow (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers (HTTP 200)
  • 29 September 2026: the link answers (HTTP 200)
4 files

jianghao-liu/attention-conscious-report

License: none: the authors keep all their rights
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: d6ae07f3f65a245684ade37d9a862e426ad37396, 12 April 2026
Languages: MATLAB (2), Jupyter (1)
Size: 4 files, 3 scripts
Software Heritage: archived
Found in: the Zenodo archive record
Holds: README, 1 notebook
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: Matplotlib (1 file), NumPy (1 file), scikit-learn (1 file), SciPy (1 file), statsmodels (1 file), TensorFlow (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
4 files

Code availability

The custom codes for trajectory k-mean clustering analysis are available at the Github https://github.com/jianghao-liu/attentionconscious-report, with the identifie80 https://doi.org/10.5281/zenodo.8113973 (https://zenodo.org/badge/latestdoi/658009571).

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

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:

  • 3 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 6 scripts, each with its path and the digest of its content;
  • 2 matches 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

The intracranial and surface data that support the findings of this study are available from the corresponding author, S. Lo, upon reasonable request.

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 1, 29 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 9 authors, 6 keywords, 5 funders, 26 references.

Cite

This paper

Lozito, S., Lasaponara, S., Liu, J., Navarro, V., Lehongre, K., Frazzini, V., Seidel Malkinson, T., Doricchi, F., & Bartolomeo, P. (2026). Towards a bridge between intracerebral and surface EEG signatures of conscious report. Neuroscience of consciousness, 2026(1), niag011. https://doi.org/10.1093/nc/niag011

BibTeX

@article{lozito2026towards,
author = {Lozito, Silvana and Lasaponara, Stefano and Liu, Jianghao and Navarro, Vincent and Lehongre, Katia and Frazzini, Valerio and Seidel Malkinson, Tal and Doricchi, Fabrizio and Bartolomeo, Paolo},
title = {{Towards a bridge between intracerebral and surface EEG signatures of conscious report}},
journal = {Neuroscience of consciousness},
year = {2026},
month = apr,
volume = {2026},
number = {1},
pages = {niag011},
publisher = {Oxford University Press},
issn = {2057-2107},
doi = {10.1093/nc/niag011},
url = {https://doi.org/10.1093/nc/niag011},
pmid = {41969663},
pmcid = {PMC13069880}
}

RIS

TY - JOUR
AU - Lozito, Silvana
AU - Lasaponara, Stefano
AU - Liu, Jianghao
AU - Navarro, Vincent
AU - Lehongre, Katia
AU - Frazzini, Valerio
AU - Seidel Malkinson, Tal
AU - Doricchi, Fabrizio
AU - Bartolomeo, Paolo
TI - Towards a bridge between intracerebral and surface EEG signatures of conscious report
T2 - Neuroscience of consciousness
J2 - Neurosci Conscious
PY - 2026
DA - 2026/04/08
VL - 2026
IS - 1
SP - niag011
SN - 2057-2107
PB - Oxford University Press
DO - 10.1093/nc/niag011
UR - https://doi.org/10.1093/nc/niag011
LA - en
ER -

CSL-JSON

{
"id": "10.1093/nc/niag011",
"type": "article-journal",
"title": "Towards a bridge between intracerebral and surface EEG signatures of conscious report",
"container-title": "Neuroscience of consciousness",
"author": [
{
"family": "Lozito",
"given": "Silvana"
},
{
"family": "Lasaponara",
"given": "Stefano"
},
{
"family": "Liu",
"given": "Jianghao"
},
{
"family": "Navarro",
"given": "Vincent"
},
{
"family": "Lehongre",
"given": "Katia"
},
{
"family": "Frazzini",
"given": "Valerio"
},
{
"family": "Seidel Malkinson",
"given": "Tal"
},
{
"family": "Doricchi",
"given": "Fabrizio"
},
{
"family": "Bartolomeo",
"given": "Paolo"
}
],
"container-title-short": "Neurosci Conscious",
"volume": "2026",
"issue": "1",
"page": "niag011",
"DOI": "10.1093/nc/niag011",
"PMID": "41969663",
"PMCID": "PMC13069880",
"ISSN": "2057-2107",
"publisher": "Oxford University Press",
"URL": "https://doi.org/10.1093/nc/niag011",
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
8
]
]
}
}

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.1093/braincomms/fcag130 [code]
Sleep increases firing rate modulation during interictal epileptiform discharges in mesial temporal structures.
Journal: Brain communications
In common: EEG, 1 reference, 2 authors
[2] doi:10.1371/journal.pbio.3003894
Sequential neural dynamics underlie unconscious integration and conscious perception of visual stimuli.
Journal: PLoS biology
In common: EEG, cognitive, 5 references
[3] doi:10.1093/nc/niag042
Early correlates of visual awareness are affected by self-related information.
Journal: Neuroscience of consciousness
In common: EEG, cognitive, 5 references
[4] doi:10.1093/nc/niag029 [code]
A data-driven approach to identifying and evaluating connectivity-based neural correlates of conscious visual perception.
Journal: Neuroscience of consciousness
In common: statsmodels, scikit-learn, SciPy, 2 other tools, cognitive, 2 references
[5] doi:10.3390/s26175327 [code]
Subject Identity Confounds qEEG Emotion Recognition on DEAP and DREAMER.
Journal: Sensors (Basel, Switzerland)
In common: TensorFlow, statsmodels, scikit-learn, 3 other tools, EEG, cognitive
[6] doi:10.1016/j.isci.2026.115785 [code]
Integrating metacognitive mechanisms optimizes EEG generative models via hierarchical regularization.
Journal: iScience
In common: TensorFlow, scikit-learn, SciPy, 2 other tools, EEG, cognitive, 1 reference
[7] doi:10.1002/ana.78203 [code]
AI-Driven Mapping of Seizure Spread Patterns.
Journal: Annals of neurology
In common: TensorFlow, statsmodels, scikit-learn, 3 other tools, EEG
[8] doi:10.1038/s41467-026-75455-1 [code]
Shared latent representations of speech production for cross-patient speech decoding.
Journal: Nature communications
In common: TensorFlow, statsmodels, scikit-learn, 3 other tools, cognitive
[9] doi:10.1002/advs.202523009 [code]
Personalized Network-Guided Neuromodulation Enhances Human Working Memory.
Journal: Advanced science (Weinheim, Baden-Wurttemberg, Germany)
In common: TensorFlow, statsmodels, scikit-learn, 3 other tools, cognitive
[10] doi:10.1038/s42003-026-10957-8 [code]
Brain defence by the extracellular matrix protein Cochlin.
Journal: Communications biology
In common: TensorFlow, statsmodels, scikit-learn, 3 other tools

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.