def calculateTransientTime(self, inputs, outputs, epsilon, proximityLength = None): # inputs: input of reserovoir # outputs: output of reservoir # epsilon: given constant # proximity length: number of steps for which all states have to be epsilon close to declare convergance # initializes two initial states as far as possible from each other in [-1,1] regime and tests when they converge-> this is transient time length = inputs.shape[0] if inputs is not None else outputs.shape[0] if proximityLength is None: proximityLength = int(length * 0.1) if proximityLength < 3: proximityLength = 3 initial_x = B.empty((2, self.n_reservoir, 1)) initial_x[0] = - B.ones((self.n_reservoir, 1)) initial_x[1] = B.ones((self.n_reservoir, 1)) countedConsecutiveSteps = 0 length = inputs.shape[0] if inputs is not None else outputs.shape[0] for t in range(length): if B.max(B.ptp(initial_x, axis=0)) < epsilon: if countedConsecutiveSteps >= proximityLength: return t - proximityLength else: countedConsecutiveSteps += 1 else: countedConsecutiveSteps = 0 u = inputs[t].reshape(-1, 1) if inputs is not None else None o = outputs[t].reshape(-1, 1) if outputs is not None else None for i in range(initial_x.shape[0]): self.update(u, o, initial_x[i]) #transient time could not be determined raise ValueError("Transient time could not be determined - maybe the proximityLength is too big.")
def getEquilibriumState(inputs, outputs, epsilon = 1e-3): # inputs: input of reserovoir # outputs: output of reservoir # epsilon: given constant # returns the equilibrium state when esn is fed with the first state of input x = B.empty((2, self.n_reservoir, 1)) while not B.max(B.ptp(x, axis=0)) < epsilon: x[0] = x[1] u = inputs[0].reshape(-1, 1) if inputs is not None else None o = outputs[0].reshape(-1, 1) if outputs is not None else None self.update(u, o, x[1]) return x[1]
def calculate_esn_mi_input_scaling(input_data, output_data): if len(input_data) != len(output_data): raise ValueError( "input_data and output_data do not have the same length - {0} vs. {1}" .format(len(input_data), len(output_data))) # Scott's rule to calculate nbins std_output = B.std(output_data) nbins = int( B.ceil(2.0 / (3.5 * std_output / B.power(len(input_data), 1.0 / 3.0)))) mi = B.zeros(input_data.shape[1]) for i in range(len(mi)): mi[i] = calculate_mutualinformation(input_data[:, i], output_data, nbins) scaling = mi / B.max(mi) return scaling
def reduceTransientTime(self, inputs, outputs, initialTransientTime, epsilon = 1e-3, proximityLength = 50): # inputs: input of reserovoir # outputs: output of reservoir # epsilon: given constant # proximity length: number of steps for which all states have to be epsilon close to declare convergance # initialTransientTime: transient time with calculateTransientTime() method estimated # finds initial state with lower transient time and sets internal state to this state # returns the new transient time by calculating the convergence time of initial states found with SWD and Equilibrium method def getEquilibriumState(inputs, outputs, epsilon = 1e-3): # inputs: input of reserovoir # outputs: output of reservoir # epsilon: given constant # returns the equilibrium state when esn is fed with the first state of input x = B.empty((2, self.n_reservoir, 1)) while not B.max(B.ptp(x, axis=0)) < epsilon: x[0] = x[1] u = inputs[0].reshape(-1, 1) if inputs is not None else None o = outputs[0].reshape(-1, 1) if outputs is not None else None self.update(u, o, x[1]) return x[1] def getStateAtGivenPoint(inputs, outputs, targetTime): # inputs: input of reserovoir # outputs: output of reservoir # targetTime: time at which the state is wanted # propagates the inputs/outputs till given point in time and returns the state of the reservoir at this point x = B.zeros((self.n_reservoir, 1)) length = inputs.shape[0] if inputs is not None else outputs.shape[0] length = min(length, targetTime) for t in range(length): u = inputs[t].reshape(-1, 1) if inputs is not None else None o = outputs[t].reshape(-1, 1) if outputs is not None else None self.update(u, o, x) return x length = inputs.shape[0] if inputs is not None else outputs.shape[0] if proximityLength is None: proximityLength = int(length * 0.1) if proximityLength < 3: proximityLength = 3 x = B.empty((2, self.n_reservoir, 1)) equilibriumState = getEquilibriumState(inputs, outputs) if inputs is None: swdPoint, _ = hp.SWD(outputs, int(initialTransientTime*0.8)) else: swdPoint, _ = hp.SWD(inputs, int(initialTransientTime * 0.8)) swdState = getStateAtGivenPoint(inputs, outputs, swdPoint) x[0] = equilibriumState x[1] = swdState transientTime = 0 countedConsecutiveSteps = 0 for t in range(length): if B.max(B.ptp(x, axis=0)) < epsilon: countedConsecutiveSteps += 1 if countedConsecutiveSteps > proximityLength: transientTime = t - proximityLength break else: countedConsecutiveSteps = 0 u = inputs[t].reshape(-1, 1) if inputs is not None else None o = outputs[t].reshape(-1, 1) if outputs is not None else None for i in range(x.shape[0]): self.update(u, o, x[i]) self._x = x[0] return transientTime
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