def update(self, inputData, outputData=None, x=None): if x is None: x = self._x if self._WFeedback is None: #reshape the data u = inputData.reshape(self.n_input, 1) #update the states transmission = self.calculateLinearNetworkTransmissions(u, x) x *= (1.0-self._leakingRate) x += self._leakingRate * self._activation(transmission + (B.rand()-0.5)*self._noiseLevel) return u, x else: #the input is allowed to be "empty" (size=0) if self.n_input != 0: #reshape the data u = inputData.reshape(self.n_input, 1) outputData = outputData.reshape(self.n_output, 1) #update the states transmission = self.calculateLinearNetworkTransmissions(u, x) x *= (1.0-self._leakingRate) x += self._leakingRate*self._activation(transmission + B.dot(self._WFeedback, B.vstack((B.array(self._outputBias), outputData))) + (B.rand()-0.5)*self._noiseLevel) return u, x else: #reshape the data outputData = outputData.reshape(self.n_output, 1) #update the states transmission = B.dot(self._W, x) x *= (1.0-self._leakingRate) x += self._leakingRate*self._activation(transmission + B.dot(self._WFeedback, B.vstack((B.array(self._outputBias), outputData))) + (B.rand()-0.5)*self._noiseLevel) return np.empty((0, 1)), x
def create_random_rotation_matrix(self): h = B.randint(low=0, high=self.n_reservoir) k = B.randint(low=0, high=self.n_reservoir) phi = B.rand(1) * 2 * np.pi Q = B.identity(self.n_reservoir) Q[h, h] = B.cos(phi) Q[k, k] = B.cos(phi) Q[h, k] = -B.sin(phi) Q[k, h] = B.sin(phi) return Q
def _createInputMatrix(self): #random weight matrix for the input from -0.5 to 0.5 self._WInput = B.rand(self.n_reservoir, 1 + self.n_input)-0.5 #scale the inputDensity to prevent saturated reservoir nodes if (self.inputDensity != 1.0): #make the input matrix as dense as requested input_topology = (np.ones_like(self._WInput) == 1.0) nb_non_zero_input = int(self.inputDensity * self.n_input) for n in range(self.n_reservoir): input_topology[n][rnd.permutation(np.arange(1+self.n_input))[:nb_non_zero_input]] = False self._WInput[input_topology] = 0.0 self._WInput = self._WInput * self._expandedInputScaling
def _createReservoir(self, weightGeneration, feedback=False, verbose=False): #naive generation of the matrix W by using random weights if weightGeneration == 'naive': #random weight matrix from -0.5 to 0.5 self._W = B.array(rnd.rand(self.n_reservoir, self.n_reservoir) - 0.5) #set sparseness% to zero mask = rnd.rand(self.n_reservoir, self.n_reservoir) > self._reservoirDensity self._W[mask] = 0.0 _W_eigenvalues = B.abs(B.eigenval(self._W)[0]) self._W *= self._spectralRadius / B.max(_W_eigenvalues) #generation using the SORM technique (see http://ftp.math.uni-rostock.de/pub/preprint/2012/pre12_01.pdf) elif weightGeneration == "SORM": self._W = B.identity(self.n_reservoir) number_nonzero_elements = self._reservoirDensity * self.n_reservoir * self.n_reservoir i = 0 while np.count_nonzero(self._W) < number_nonzero_elements: i += 1 Q = self.create_random_rotation_matrix() self._W = Q.dot(self._W) self._W *= self._spectralRadius #generation using the proposed method of Yildiz elif weightGeneration == 'advanced': #two create W we must follow some steps: #at first, create a W = |W| #make it sparse #then scale its spectral radius to rho(W) = 1 (according to Yildiz with x(n+1) = (1-a)*x(n)+a*f(...)) #then change randomly the signs of the matrix #random weight matrix from 0 to 0.5 self._W = B.array(rnd.rand(self.n_reservoir, self.n_reservoir) / 2) #set sparseness% to zero mask = B.rand(self.n_reservoir, self.n_reservoir) > self._reservoirDensity self._W[mask] = 0.0 from scipy.sparse.linalg.eigen.arpack.arpack import ArpackNoConvergence #just calculate the largest EV - hopefully this is the right code to do so... try: #this is just a good approximation, so this code might fail _W_eigenvalue = B.max(np.abs(sp.sparse.linalg.eigs(self._W, k=1)[0])) except ArpackNoConvergence: #this is the safe fall back method to calculate the EV _W_eigenvalue = B.max(B.abs(sp.linalg.eigvals(self._W))) #_W_eigenvalue = B.max(B.abs(np.linalg.eig(self._W)[0])) self._W *= self._spectralRadius / _W_eigenvalue if verbose: M = self._leakingRate*self._W + (1 - self._leakingRate)*np.identity(n=self._W.shape[0]) M_eigenvalue = B.max(B.abs(B.eigenval(M)[0]))#np.max(np.abs(sp.sparse.linalg.eigs(M, k=1)[0])) print("eff. spectral radius: {0}".format(M_eigenvalue)) #change random signs random_signs = B.power(-1, rnd.random_integers(self.n_reservoir, self.n_reservoir)) self._W = B.multiply(self._W, random_signs) elif weightGeneration == 'custom': pass else: raise ValueError("The weightGeneration property must be one of the following values: naive, advanced, SORM, custom") #check of the user is really using one of the internal methods, or wants to create W by his own if (weightGeneration != 'custom'): self._createInputMatrix() #create the optional feedback matrix if feedback: self._WFeedback = B.rand(self.n_reservoir, 1 + self.n_output) - 0.5 self._WFeedback *= self._feedbackScaling else: self._WFeedback = None
def _createReservoir(self, weightGeneration, feedback=False, verbose=False): # naive generation of the matrix W by using random weights if weightGeneration == "naive": # random weight matrix from -0.5 to 0.5 self._W = B.array(B.rand(self.n_reservoir, self.n_reservoir) - 0.5) # set sparseness% to zero mask = B.rand(self.n_reservoir, self.n_reservoir) > self._reservoirDensity self._W[mask] = 0.0 _W_eigenvalues = B.abs(B.eigenval(self._W)[0]) self._W *= self._spectralRadius / B.max(_W_eigenvalues) # generation using the SORM technique (see http://ftp.math.uni-rostock.de/pub/preprint/2012/pre12_01.pdf) elif weightGeneration == "SORM": self._W = B.identity(self.n_reservoir) number_nonzero_elements = (self._reservoirDensity * self.n_reservoir * self.n_reservoir) i = 0 while B.count_nonzero(self._W) < number_nonzero_elements: i += 1 Q = self.create_random_rotation_matrix() self._W = Q.dot(self._W) self._W *= self._spectralRadius # generation using the proposed method of Yildiz elif weightGeneration == "advanced": # two create W we must follow some steps: # at first, create a W = |W| # make it sparse # then scale its spectral radius to rho(W) = 1 (according to Yildiz with x(n+1) = (1-a)*x(n)+a*f(...)) # then change randomly the signs of the matrix # random weight matrix from 0 to 0.5 self._W = B.array(B.rand(self.n_reservoir, self.n_reservoir) / 2) # set sparseness% to zero mask = B.rand(self.n_reservoir, self.n_reservoir) > self._reservoirDensity self._W[mask] = 0.0 _W_eigenvalue = B.max(B.abs(B.eigvals(self._W))) self._W *= self._spectralRadius / _W_eigenvalue if verbose: M = self._leakingRate * self._W + ( 1 - self._leakingRate) * B.identity(n=self._W.shape[0]) M_eigenvalue = B.max(B.abs(B.eigenval(M)[0])) print("eff. spectral radius: {0}".format(M_eigenvalue)) # change random signs random_signs = B.power(-1, B.randint(1, 3, (self.n_reservoir, ))) self._W = B.multiply(self._W, random_signs) elif weightGeneration == "custom": pass else: raise ValueError( "The weightGeneration property must be one of the following values: naive, advanced, SORM, custom" ) # check of the user is really using one of the internal methods, or wants to create W by his own if weightGeneration != "custom": self._createInputMatrix() # create the optional feedback matrix if feedback: self._WFeedback = B.rand(self.n_reservoir, 1 + self.n_output) - 0.5 self._WFeedback *= self._feedbackScaling else: self._WFeedback = None