├── filtered_data.mat ├── README.md ├── FeedbackNet.py ├── EHRule.py ├── nn.py └── ReservoirNodes.py /filtered_data.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AminaKeldibek/chaotic_RNN/HEAD/filtered_data.mat -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chaotic Recurrent Neural Networks 2 | Implementation of RNN model described in "Generating Coherent Patterns of Activity from Chaotic Neural Networks" (David Sussillo and L. F. Abbott, 2009, http://www.theswartzfoundation.org/docs/Sussillo-Abbott-Coherent-Patterns-August-2009.pdf) 3 | 4 | **filtered_data.mat** is obtained from VRep Robotics simulator (Asimo robot). Smoothing using moving average filter was applied to data. 5 | 6 | -------------------------------------------------------------------------------- /FeedbackNet.py: -------------------------------------------------------------------------------- 1 | """RNN model.""" 2 | 3 | import numpy as np 4 | 5 | class FeedbackNet: 6 | """Create RNN model.""" 7 | 8 | def __init__(self, reservoir, weights, noise_level): 9 | """ 10 | Parameters 11 | ---------- 12 | reservoir : ReservoirNodes 13 | Reservoir node with leaky integrator neurons. 14 | 15 | weights : numpy.ndarray, shape = [number of neurons, number of readout neurons] 16 | Output synapes weights 17 | 18 | noise_level : float 19 | Noise in the firing rate of readout neurons, from a uniform distribution in the interval [-0.5 0.5] 20 | """ 21 | self.res = reservoir 22 | self.weights = weights 23 | self.noise_level = 2 * noise_level 24 | self.feedback = 0.5 * np.random.randn(1, self.weights.shape[1]) 25 | self.__outsize = self.weights.shape[1] 26 | 27 | def simulate(self, inp=None): 28 | out = np.zeros((inp.shape[0], self.__outsize)) 29 | idx = 0 30 | 31 | for i in inp: 32 | r = self.res.simulate(i, self.feedback) 33 | self.feedback = np.dot(r, self.weights) + self.noise_level*(np.random.rand(1, self.__outsize)-0.5) 34 | out[idx, :] = np.transpose(self.feedback) 35 | idx = idx+1 36 | self.feedback = self.feedback 37 | 38 | return out 39 | 40 | def simulateNoInput(self, steps): 41 | """Generate RNN model output. 42 | Parameters 43 | ---------- 44 | steps : int 45 | Number of samples to generate. 46 | 47 | Returns 48 | ------- 49 | out : numpy.ndarray shape = [number of samples, number of readout neurons] 50 | RNN output. 51 | """ 52 | out = np.zeros((steps, self.__outsize)) 53 | 54 | for k in xrange(0, steps): 55 | r = self.res.simulate(self.feedback) 56 | self.feedback = np.dot(r, self.weights) + self.noise_level*(np.random.rand(1, self.__outsize)-0.5) 57 | out[k, :] = self.feedback 58 | 59 | return out 60 | -------------------------------------------------------------------------------- /EHRule.py: -------------------------------------------------------------------------------- 1 | """Train RNN.""" 2 | 3 | # Author: Amina Keldibek 4 | 5 | import numpy as np 6 | from FeedbackNet import FeedbackNet 7 | 8 | 9 | class EHRule: 10 | """Create object for RNN training.""" 11 | 12 | def __init__(self, reservoir, learn_rate_init, t_avg, decay_const): 13 | """ 14 | Parameters 15 | ---------- 16 | reservoir : ReservoirNodes 17 | Reservoir node with leaky integrator neurons. 18 | 19 | learn_rate_init : float 20 | Initial learning rate. 21 | 22 | t_avg : float 23 | Average time for decaying learning rate. 24 | 25 | decay_const : int 26 | Decay constant. 27 | """ 28 | self.__res = reservoir 29 | self.__t_avg = t_avg 30 | self.learn_rate_init = learn_rate_init 31 | self.decay_const = decay_const 32 | 33 | def train(self, output, step, inp=None): 34 | """Train RNN. 35 | Parameters: 36 | output: numpy.ndarray, shape = [number of samples, number of readout neurons] 37 | Data to train RNN 38 | step: float 39 | sampling step for training data 40 | inp: ***not implemented yet (used for controlling output pattern)*** 41 | 42 | Returns 43 | ------- 44 | model : trained RNN model 45 | out : output of RNN during training phase 46 | """ 47 | alpha = 1 - self.__res.time_step / self.__t_avg 48 | out_size = output.shape[1] 49 | weights_out = np.zeros((self.__res.network_size, out_size)) 50 | z = np.zeros((1, out_size)) 51 | plp = 0 52 | zlp = np.zeros((1, out_size)) 53 | out = np.zeros((output.size, out_size)) 54 | 55 | for idx in xrange(0, output.shape[0], step): 56 | r = self.__res.simulate(z, inp) 57 | z = np.dot(r, weights_out) + np.random.rand(1, out_size) - 0.5 58 | 59 | p = -np.sum(np.power(z - output[idx], 2)) 60 | plp = alpha * plp + (1 - alpha) * p 61 | zlp = alpha * zlp + (1 - alpha) * z 62 | 63 | if p > plp: 64 | eta = self.learn_rate_init / (1 + idx * self.__res.time_step / self.decay_const) 65 | dw = eta * np.multiply(np.transpose(z-zlp), r) 66 | weights_out = weights_out + np.transpose(dw) 67 | out[idx, :] = zlp 68 | 69 | model = FeedbackNet(self.__res, weights_out, 0.5) 70 | return model, out 71 | -------------------------------------------------------------------------------- /nn.py: -------------------------------------------------------------------------------- 1 | """ 2 | Recurrent Neural Network (RNN). 3 | 4 | This is an implementation of the RNN model described in: 5 | Hoerzer, G., Legenstein, R., & Maass, W. (2012). 6 | Emergence of Complex Computational Structures From Chaotic 7 | Neural Networks Through Reward-Modulated Hebbian Learning. 8 | Cerebral Cortex, 24(3), 677-690. 9 | """ 10 | 11 | # Author : Amina Keldibek 12 | 13 | from ReservoirNodes import ReservoirNodes 14 | from EHRule import EHRule 15 | from scipy.io import loadmat 16 | from numpy import zeros 17 | import matplotlib.pyplot as plt 18 | 19 | 20 | def train(data): 21 | """Train RNN. 22 | Parameters 23 | ---------- 24 | data: numpy.ndarray, shape = [number of samples, number of readout neurons] 25 | Data to train RNN 26 | 27 | Returns 28 | ------- 29 | model : trained RNN model 30 | train_out : output of RNN during training phase 31 | """ 32 | network_size = 1000 33 | input_size = 0 34 | connect_prob = 0.1 35 | chaoticity_level = 1.7 36 | time_const = 10e-3 37 | noise_level = 0.05 38 | time_step = 1e-3 39 | 40 | learn_rate_init = 0.001 41 | t_avg = 2e-3 42 | decay_const = 20 43 | 44 | reservoir = ReservoirNodes(input_size, data.shape[1], network_size, 45 | time_const, connect_prob, chaoticity_level, 46 | noise_level, time_step) 47 | trainer = EHRule(reservoir, learn_rate_init, t_avg, decay_const) 48 | 49 | model, train_out = trainer.train(data, 1) 50 | 51 | return model, train_out 52 | 53 | 54 | def test(N, model): 55 | """Generate RNN output 56 | Parameters 57 | ---------- 58 | N: integer 59 | Number of samples to be generated 60 | model: FeedbackNet object 61 | RNN model 62 | 63 | Returns 64 | ------- 65 | model : trained RNN model 66 | output : output of RNN model of size N 67 | """ 68 | out_test = model.simulateNoInput(int(N)) 69 | 70 | return out_test 71 | 72 | 73 | def driver(): 74 | data = loadmat('filtered_data.mat') 75 | 76 | trainTime = 20000 77 | testTime = 1000 78 | numOfJoints = 1 79 | 80 | # train model 81 | model, out_train = train(data['jointTrajFilt'][0:trainTime, 0:numOfJoints]) 82 | 83 | # test model 84 | model.noise_level = 0 85 | model.feedback = out_train[-1,:] 86 | out_test = test(testTime, model) 87 | 88 | """# RMS 89 | rms = zeros(numOfJoints) 90 | for i in range(0, numOfJoints): 91 | rms[i] = sqrt(((out_test[:,i] - data['jointTrajFilt'][trainTime:trainTime+testTime,i] ) ** 2).mean()) 92 | print (rms)""" 93 | 94 | # visualize output 95 | plt.figure(1) 96 | # RNN output during training phase 97 | plt.plot(out_train, 'r', data['jointTrajFilt'][0:trainTime-1,0], 'g') 98 | plt.figure(2) 99 | # RNN output 100 | plt.plot(out_test, 'r', data['jointTrajFilt'][trainTime:trainTime+testTime,0], 'g') 101 | plt.show() 102 | 103 | 104 | if __name__ == "__main__": 105 | driver() 106 | -------------------------------------------------------------------------------- /ReservoirNodes.py: -------------------------------------------------------------------------------- 1 | """Reservoir node with leaky integrator neurons.""" 2 | 3 | # Author: Amina Keldibek 4 | 5 | from math import sqrt 6 | from scipy import sparse 7 | from numpy import random, tanh, dot 8 | 9 | 10 | class ReservoirNodes: 11 | """Create reservoir node.""" 12 | 13 | def __init__(self, input_size, out_size, network_size, time_const, 14 | connect_prob, chaoticity_level, noise_level, time_step): 15 | """ 16 | Parameters 17 | ---------- 18 | input_size : integer 19 | Size of input signal to the network. 20 | 21 | out_size : integer 22 | Number of readout neurons. 23 | 24 | network_size : integer 25 | Number of neurons. 26 | 27 | time_const : float 28 | Membrane time constant. 29 | 30 | connect_prob : float 31 | Probability of neurons connectivity in RNN. 32 | 33 | chaoticity_level : float 34 | Parameter for different dynamic regime of the network 35 | (from ordered to chaotic, good values are 1.5-1.7). 36 | 37 | noise_level : float 38 | Exploration noise. 39 | 40 | time_step : float 41 | Simulation time step. 42 | 43 | """ 44 | self.input_size = input_size 45 | self.network_size = network_size 46 | self.__time_const = time_const 47 | self.noise_level = 2 * noise_level 48 | self.time_step = time_step 49 | 50 | self.__R = sparse.rand(network_size, network_size, 51 | density=connect_prob, format='csr') 52 | scale = 1 / sqrt(connect_prob * network_size) 53 | self.__R = self.__R * scale * chaoticity_level * time_step 54 | 55 | self.__weights_feedback = (random.rand(out_size, network_size) - 0.5) 56 | self.__weights_feedback = 2 * time_step * self.__weights_feedback 57 | 58 | self.__weights_input = (random.rand(input_size, network_size) - 0.5) 59 | self.__weights_input = 2 * time_step * self.__weights_input 60 | 61 | self.__states = 0.5 * random.randn(1, network_size) 62 | 63 | self.__prev_out = tanh(self.__states) 64 | 65 | def simulate(self, z, inp=None): 66 | """Simulate RNN dynamics. 67 | Parameters 68 | ---------- 69 | z : numpy.ndarray 70 | Readout output. 71 | 72 | inp : numpy.ndarray 73 | Control input to the network. 74 | 75 | Returns 76 | ------- 77 | __prev_out : numpy.ndarray 78 | Previous output. 79 | 80 | """ 81 | if inp is None: 82 | self.__states = ((1 - self.time_step / self.__time_const) * \ 83 | self.__states + \ 84 | (self.__prev_out * self.__R + \ 85 | dot(z, self.__weights_feedback)) / \ 86 | self.__time_const) 87 | else: 88 | self.__states = ((1 - self.time_step / self.__time_const) * \ 89 | self.__states + \ 90 | (self.__prev_out*self.__R + \ 91 | dot(z, self.__weights_feedback) + \ 92 | dot(inp, self.__weights_input)) / \ 93 | self.__time_const) 94 | 95 | self.__prev_out = tanh(self.__states) + self.noise_level * \ 96 | (random.rand(1, self.network_size) - 0.5) 97 | 98 | return self.__prev_out 99 | --------------------------------------------------------------------------------