def reset(self, **kwargs): IterativeAlgorithm.reset(self) # memberships = [self.normalize([random() for j in range(self.n_clusters)]) for i in range(len(self.sample))] # self.model = FuzzyCMeansClusterer(self.sample, memberships) if self.initializer: self.n_clusters = len(self.initializer) centroids = self.initializer data = array([elem.pattern for elem in self.sample]) memberships = [self.normalize([random() for j in range(self.n_clusters)]) for i in range(len(self.sample))] for j in range(len(centroids)): for i in range(len(data)): den = sum([(linalg.norm(data[i] - centroids[j])/ linalg.norm(data[i]-centroids[k]))**(2/(self.m-1)) for k in range(self.n_clusters)]) memberships[i][j] = 1/den else: memberships = [self.normalize([random() for j in range(self.n_clusters)]) for i in range(len(self.sample))] self.model = FuzzyCMeansClusterer(self.sample, memberships) # 10 means simply a big value, so that we don't run the risk of erronously stop # if we check convergence before first iteration self.memberships_old = [[10 for j in range(self.n_clusters)] for i in range(len(self.sample))]
def __init__(self, sample, **kwargs): r""" See ``RosenblattPerceptronAlgorithm`` for full definition. """ PerceptronAlgorithm.__init__(self, sample, **kwargs) IterativeAlgorithm.__init__(self, sample) PerceptronAlgorithm.reset(self, **kwargs)
def __init__(self, sample, **kwargs): r""" See ``GradientPerceptronAlgorithm`` for full documentation. """ PerceptronAlgorithm.__init__(self, sample, **kwargs) IterativeAlgorithm.__init__(self, sample) # This calms down pylint self.beta = None self.reset(**kwargs)
def __init__(self, sample, n_clusters = 2, m = 2, **kwargs ): IterativeAlgorithm.__init__(self, sample) try: self.initializer = kwargs['initializer'] except KeyError: self.initializer = False self.n_clusters = n_clusters self.m = m self.distance = 1.0 #self.reset(**kwargs) self.memberships_old = None self.reset(**kwargs)
def run(self, **kwargs): IterativeAlgorithm.run(self, **kwargs) data = array([elem.pattern for elem in self.sample]) while self.stop_criterion.stop() == False: self.memberships_old = self.matrix_copy(self.model.memberships) #print self.model.memberships centroids = self.model.getCentroids(m= self.m) #print centroids #exit() for j in range(len(centroids)): for i in range(len(data)): den = sum([(linalg.norm(data[i] - centroids[j])/ linalg.norm(data[i]-centroids[k]))**(2/(self.m-1)) for k in range(self.n_clusters)]) self.model.memberships[i][j] = 1/den self.notify_observers()
def __init__(self, sample, dimensions=None, **kwargs): r""" See ``BackpropagationAlgorithm`` for full documentation. """ IterativeAlgorithm.__init__(self, sample) # dimensions needs to be a named argument in order to be able to # cross-validate on it. The default value will correspond to three # layers, with the input and output one automatically sized in order # to fit the provided data set, and the hidden one containing half of # the biggest value between number of input and output units. if dimensions is not None: self.dimensions = dimensions else: n_in = len(sample[0].pattern) n_out = len(sample[0].label) self.dimensions = (n_in, int(max(n_in, n_out) / 2), n_out) num_input = self.dimensions[0] for example in sample: if len(example.pattern) != num_input: raise ValueError('Sample incompatible with number of units') try: self.activations = kwargs['activations'] if len(self.activations) != len(dimensions): raise ValueError(\ 'Activations incompatible with number of layers') except KeyError: self.activations = SigmoidActivationFunction() except TypeError: pass # Raised by len if the argument is assigned a single activation # this calms down pylint self.threshold = None self.reset(**kwargs)
def run(self, **kwargs): r""" Run the learning algorithm. INPUT: - ``self`` -- object on which the function is invoked. - ``stopping_criterion`` -- ``StoppingCriterion`` instance (default: ``FixedIterationsStoppingCriterion()``, amounting to the execution of one learning step) describing the criterion to be fulfilled in order to stop the training phase. - ``batch`` -- boolean (default: ``False``, amounting to online learning mode) flag setting batch learning, i.e. model update after the presentation of all examples, instead of online learning, i.e. model update at each example presentation. - ``selector`` -- iterator (default: ``sequential_selector``, amounting to cycling through the available examples) selecting the next sample to be fed to the learnin algorithm. - ``learning_rate`` -- float (default: 0.1) value to be used as learning rate. - ``momentum_term`` -- float (default: 0) value tu be used as momentum term. - ``min_error`` -- float (default: 0, which means connections and thresholds will always be updated) error value under which no update will occur on connections and thresholds. OUTPUT: No output. After the invocation the inferred model is available through the ``model`` field, in form of a ``Perceptron`` instance. EXAMPLES: Consider the following data set summarizing the binary XOR function, and a ``BackpropagationAlgorithm`` instance for it: :: >>> from yaplf.data import LabeledExample >>> xor_sample = [LabeledExample((0, 0), (0,)), ... LabeledExample((0, 1), (1,)), LabeledExample((1, 0), (1,)), ... LabeledExample((1, 1), (0,))] >>> from yaplf.utility import SigmoidActivationFunction >>> from yaplf.algorithms.neural import BackpropagationAlgorithm >>> alg = BackpropagationAlgorithm(xor_sample, (2, 2, 1), ... threshold = True, activations = SigmoidActivationFunction(10)) In order to actually run the algorithm it is necessary to specify a stopping criterion (the default behaviour would only execute a learning iteration, probably not going so far). In order to keep it simple, one can chose ``FixedIterationsStoppingCriterion`` so as to run a fixed number of iterations, say `5000`: :: >>> from yaplf.utility.stopping import \ ... FixedIterationsStoppingCriterion >>> alg.run(stopping_criterion = \ ... FixedIterationsStoppingCriterion(5000), learning_rate = .1) The inferred model can be inspected through the ``model`` field in the ``LearningAlgorithm`` object: :: >>> alg.model # random MultilayerPerceptron((2, 2, 1), [array([[-0.49748418, -0.48592928], [-0.72052151, -0.69609958]]), array([[ 0.78258238, -0.84286672]])], thresholds = [array([ 0.71869556, 0.24337534]), array([-0.36203957])], activations = SigmoidActivationFunction(10)) One of the ways of assessing the performance of the algorithm is that of invoking the ``test`` function inherited from the ``Model`` class in order to see how each example has been classified: :: >>> alg.model.test(xor_sample, verbose = True) # random (0, 0) mapped to 0.0279358676426, label is (0,), error [ 0.00078041] (0, 1) mapped to 0.968320708961, label is (1,), error [ 0.00100358] (1, 0) mapped to 0.966511649371, label is (1,), error [ 0.00112147] (1, 1) mapped to 0.0429967333857, label is (0,), error [ 0.00184872] MSE 0.00118854472284 0.0011885447228408164 The named argument ``verbose`` activates the verbose output detailing how error spreads on each example. Note that the output of ``test`` is likely to be different on each run, as when the class constructor is called the initial weights are chosen at random. Another solution is that of running the algorithm until the error on its training set is below a given threshold. This can be easily attained using ``TrainErrorStoppingCriterion``: :: >>> from yaplf.utility.stopping import TrainErrorStoppingCriterion >>> alg = BackpropagationAlgorithm(xor_sample, (2, 2, 1), ... learning_rate = .1, ... activations = SigmoidActivationFunction(10)) >>> alg.run(stopping_criterion = TrainErrorStoppingCriterion(0.01)) The argument in the constructor of ``TrainErrorStoppingCriterion`` sets the above mentioned threshold. It is also possible (and, besides, more correct) to run the learning algorithm using a training set and stopping the process when the test error on another data set goes below a given threshold. This can be attained using ``TestErrorStoppingCriterion`` in package ``yaplf.utility.stopping``. Another way of evaluating the inferred model is in this case that of graphically visualizing it. As the perceptron has two inputs it is indeed possible to call its ``plot`` method specifying a region containing all the pattern supplied to the learning algorithm: :: >>> alg.model.plot((0, 1), (0, 1), shading = True) Learning can be also monitored using the class ``ErrorTrajectory`` in package ``yaplf.graph.trajectory`` as follows: :: >>> alg = BackpropagationAlgorithm(xor_sample, (2, 2, 1), ... activations = SigmoidActivationFunction(10)) >>> errObs = ErrorTrajectory(alg) >>> alg.run(stopping_criterion = \ ... FixedIterationsStoppingCriterion(1500)) >>> errObs.get_trajectory(color='red', joined = True) In this way, at each learning iteration the inferred model is tested against the training set, so that the ``get_trajectory`` function returns a graph of the related error versus the iteration number. The ``run`` function has a number of named argument allowing to tune how the backpropagation algorithm selects its output, and whose meaning requires a bit more information about how the algorithm works: basically, during the initialization of ``BackpropagationAlgorithm`` and at each invokation of ``reset`` a multilayer perceptron is created picking its connection weights and its threshold values at random; subsequently at each iteration an example is selected and fed to this perceptron. The obtained output is compared to the expected one and an error is computed. This error, together with other information, the computation of a quantity `\Delta w` which will in turn be used in order to modify connections and thresholds. More precisely at a given time `t`, for each connection weight, say `w_{ij}(t)`, a corresponding `\Delta w_{ij}(t)` is computed and the perceptron is updated so that `w_{ij}(t+1) = w_{ij}(t) - \eta \Delta w_{ij}(t) + \alpha \Delta w_{ij}(t-1)`. This rule implements a local descent in the error space so that eventually the obtained minimizes locally the training error. The values `\eta` and `\alpha` can be chosen through the following named arguments: - ``learning_rate`` corresponds to`\eta`, the so-called *learning rate*, with a default value of 0.1. The higher this value, the more extended will be the local steps of the algorithm. This will improve convergence but will also raise the risk of outrunning an optimum and starting to oscillate around it. - ``momentum_term`` corresponds to `\alpha`, the so-called *momentum term* as it features a momentum which increases the actual step when the surface is smooth and tends to decrement it otherwise. Its default value is 0, corresponding to the original version of the backpropagation algorithm. The following named argument also affect the learning behaviour: - ``selector`` sets an iterator selecting the next example to be fed to the learnin algorithm. Its default value cycles through the provided sample. - ``batch`` -- boolean flag setting batch learning mode, in which the update values `\Delta w_{ij}` are cumulated for all example in the sample and subsequently used in order to modify the perceptron, rather than the standard online mode where the perceptron is updated after each single example presentation. Its default value is ``False``, corresponding to the online mode previously illustrated. It is worth noting that when the algorithm is run for a fixed number of iterations (i.e. through ``FixedIterationsStoppingCriterion``), an iteration corresponds to one example presentation for online mode and to the presentation of the whole sample for batch mode. - ``min_error`` -- error value under which no update will occur on connections and thresholds. This argument can be used in order to avoid that some examples are overlearnt at the expense of the remaining ones. The default value is 0, leading to updating the perceptron regardless of how small is the error on an example. AUTHORS: - Dario Malchiodi (2010-03-31) """ IterativeAlgorithm.run(self, **kwargs) try: # batch or online learning batch = kwargs['batch'] except KeyError: batch = False try: learning_rate = kwargs['learning_rate'] except KeyError: learning_rate = 0.1 try: momentum_term = kwargs['momentum_term'] except KeyError: momentum_term = 0 try: min_error = kwargs['min_error'] except KeyError: min_error = 0 dims = transpose((self.dimensions[1:], self.dimensions[:-1])) last_delta = [zeros(shape) for shape in dims] if self.threshold: last_delta_threshold = [zeros(shape) \ for shape in self.dimensions[1:]] while self.stop_criterion.stop() == False: if batch: cumul_delta = last_delta = [zeros(shape) for shape in dims] if self.threshold: cumul_delta_thresholds = [zeros(shape) \ for shape in self.dimensions[1:]] for elem in self.sample: answer = self.model.compute(elem.pattern, full_state=True, show_net=True, no_unbox=True) delta = [[]] * (len(self.dimensions) - 1) error = transpose(answer[-1])[0] - elem.label if abs(error) < min_error: continue derivative = [\ self.model.get_activation(-1).compute_derivative(net, func_value=val) for (val, net) in answer[-1]] delta[-1] = error * derivative for lev in range(1, len(self.dimensions) - 1): derivatives = [self.model.get_activation(-lev - \ 1).compute_derivative(net, func_value=val) \ for (val, net) in answer[-lev - 1]] prop_delta = \ dot(transpose(self.model.connections[-lev]), delta[-lev]) delta[-lev - 1] = array(derivatives * prop_delta) for lev in range(1, len(self.dimensions)): new_delta = -learning_rate * outer(delta[-lev], transpose(answer[-lev - 1])[0]) + \ momentum_term * last_delta[-lev] cumul_delta[-lev] += new_delta last_delta[-lev] = new_delta if self.threshold: new_delta = -learning_rate * delta[-lev] +\ momentum_term * last_delta_threshold[-lev] cumul_delta_thresholds[-lev] += new_delta last_delta_threshold[-lev] = new_delta for lev in range(1, len(self.dimensions)): self.model.connections[-lev] += cumul_delta[-lev] if self.threshold: self.model.thresholds[-lev] += \ cumul_delta_thresholds[lev] else: elem = self.sample_selector.next() answer = self.model.compute(elem.pattern, full_state=True, show_net=True, no_unbox=True) delta = [[]] * (len(self.dimensions) - 1) error = transpose(answer[-1])[0] - elem.label if abs(error) < min_error: continue derivative = [\ self.model.get_activation(-1).compute_derivative(net, func_value=val) for (val, net) in answer[-1]] delta[-1] = error * derivative for lev in range(1, len(self.dimensions) - 1): derivatives = [self.model.get_activation(-lev - \ 1).compute_derivative(net, func_value=val) \ for (val, net) in answer[-lev - 1]] prop_delta = dot(transpose(self.model.connections[-lev]), delta[-lev]) delta[-lev - 1] = array(derivatives * prop_delta) for lev in range(1, len(self.dimensions)): new_delta = -learning_rate * outer(delta[-lev], transpose(answer[-lev - 1])[0]) + \ momentum_term * last_delta[-lev] self.model.connections[-lev] += new_delta last_delta[-lev] = new_delta if self.threshold: new_delta = -learning_rate * delta[-lev] +\ momentum_term * last_delta_threshold[-lev] self.model.thresholds[-lev] += new_delta last_delta_threshold[-lev] = new_delta self.notify_observers()
def run(self, **kwargs): r""" Run the learning algorithm. INPUT: - ``self`` -- object on which the function is invoked. - ``stopping_criterion`` -- ``StoppingCriterion`` instance (default: ``FixedIterationsStoppingCriterion()``, amounting to the execution of one learning step) describing the criterion to be fulfilled in order to stop the training phase. - ``batch`` -- boolean (default: ``False``, amounting to online learning mode) flag setting batch learning, i.e. model update after the presentation of all examples, instead of online learning, i.e. model update at each example presentation. - ``selector`` -- iterator (default: ``sequential_selector``, amounting to cycling through the available examples) selecting the next sample to be fed to the learnin algorithm. - ``learning_rate`` -- float (default: 0.1) value to be used as learning rate. OUTPUT: No output. After the invocation the inferred model is available through the ``model`` field, in form of a ``Perceptron`` instance. EXAMPLES: Consider the following data set summarizing the binary AND function, and an instance of ``GradientPerceptronAlgorithm``: :: >>> from yaplf.data import LabeledExample >>> and_sample = [LabeledExample((1, 1), (1,)), ... LabeledExample((0, 0), (0,)), LabeledExample((0, 1), (0,)), ... LabeledExample((1, 0), (0,))] >>> from yaplf.algorithms.neural import GradientPerceptronAlgorithm >>> alg = GradientPerceptronAlgorithm(and_sample, threshold = True, ... weight_bound = 0.1, beta = 0.8) In order to actually run the algorithm it is necessary to specify a stopping criterion (the default behaviour would only execute a learning iteration, probably not going so far). In order to keep it simple, one can chose ``FixedIterationsStoppingCriterion`` so as to run a fixed number of iterations, say `5000`: :: >>> from yaplf.utility.stopping import \ ... FixedIterationsStoppingCriterion >>> alg.run(stopping_criterion = \ .... FixedIterationsStoppingCriterion(5000), batch = False, ... learning_rate = .1) The inferred model can be inspected through the ``model`` field in the ``LearningAlgorithm`` object: :: >>> alg.model # random Perceptron([array([ 4.01133491, 4.00742238])], threshold = [6.1595362999239365], activation = SigmoidActivationFunction(0.800000000000000)) A better way of assessing the performance of the algorithm is that of invoking the ``test`` function inherited from the ``Model`` class in order to see how each example has been classified: :: >>> from yaplf.utility.error import MaxError >>> alg.model.test(and_sample, MaxError(), verbose = True) # random (1, 1) mapped to 0.81568421764, label is (1,), error 0.033972307625 (0, 0) mapped to 0.00719156413, label is (0,), error 5.17185946e-05 (0, 1) mapped to 0.15165346334, label is (0,), error 0.022998772945 (1, 0) mapped to 0.1520565945, label is (0,), error 0.0231212079 Maximum error: 0.0339723076259 0.033972307625870855 The second argument in ``test`` is an object subclassing ``ErrorModel``, allowing to specify a given metric in order to compute the distance between expected and actual output. The argument's default, amounting to the mean square error, has been in this case overridden to ``MaxError()``, thus computing the maximum error. As a final remark, it should be highlighted that these examples are shown for illustrative purpose. The suitable way of assessing a learnt model performance involves more complex techniques involving the use of a test set possibly coupled with a cross validation procedure (see function ``cross_validation`` in package ``yaplf.utility.validation``.) AUTHORS: - Dario Malchiodi (2010-02-22) """ IterativeAlgorithm.run(self, **kwargs) try: # batch or online learning batch = kwargs["batch"] except KeyError: batch = False try: learning_rate = kwargs["learning_rate"] except KeyError: learning_rate = 0.1 while self.stop_criterion.stop() == False: if batch: delta = array([[0.0] * len(self.sample[0].pattern) + 1] * len(self.sample[0].label)) for elem in self.sample: answer = self.model.compute(elem.pattern) if type(answer) != type(()): answer = (answer,) delta += [ 2 * self.beta * learning_rate * array( [ (answer[s] - elem.label[s]) * answer[s] * (1 - answer[s]) * hstack((elem.pattern, (-1 if self.threshold else 0)))[t] for t in range(len(self.sample[0].pattern) + 1) ] ) for s in range(len(self.sample[0].label)) ] delta = delta.tolist() else: elem = self.sample_selector.next() answer = self.model.compute(elem.pattern) if type(answer) != type(()): answer = (answer,) delta = [ 2 * self.beta * learning_rate * array( [ (answer[s] - elem.label[s]) * answer[s] * (1 - answer[s]) * hstack((elem.pattern, (-1 if self.threshold else 0)))[t] for t in range(len(self.sample[0].pattern) + 1) ] ) for s in range(len(self.sample[0].label)) ] self.model.weights = [self.model.weights[i] - delta[i] for i in range(len(delta))] self.notify_observers()
def run(self, **kwargs): r""" Run the Rosenblatt learning algorithm. INPUT: - ``self`` -- object on which the function is invoked. - ``stopping_criterion`` -- ``StoppingCriterion`` object (default: ``FixedIterationsStoppingCriterion()``, amounting to the execution of one iteration step) to be used in order to decide when learning should be stopped. - ``selector`` -- iterator (default: ``sequential_selector``) yielding the examples to be fed to the learning algorithm. OUTPUT: No output. After the invocation the inferred model is available through the ``model`` field, in form of a ``Perceptron`` instance. EXAMPLES: Consider the following linearly separable data set summarizing the binary AND function, and a ``RosenblattPerceptronAlgorithm`` instance: :: >>> from yaplf.data import LabeledExample >>> and_sample = [LabeledExample((1, 1), (1,)), ... LabeledExample((0, 0), (0,)), LabeledExample((0, 1), (0,)), ... LabeledExample((1, 0), (0,))] >>> from yaplf.algorithms.neural import \ ... RosenblattPerceptronAlgorithm >>> alg = RosenblattPerceptronAlgorithm(and_sample, ... threshold = True, weight_bound = 0.1) In order to actually run the algorithm it is necessary to specify a stopping criterion (the default behaviour would only execute a learning iteration, probably not going so far). In order to keep it simple, one can chose ``FixedIterationsStoppingCriterion`` so as to run a fixed number of iterations, say `100`: :: >>> from yaplf.utility.stopping import \ ... FixedIterationsStoppingCriterion >>> alg.run(stopping_criterion = \ ... FixedIterationsStoppingCriterion(100)) Another possible variation is that modifying the way examples are chosen and fed to the learning algorithm at each iteration. The default choice cycles between available examples, but it possible for instance to pick examples at random. This requires to specify a value for the ``selector`` named argument: :: >>> alg.reset() >>> from yaplf.utility.selection import random_selector >>> alg.run(stopping_criterion = \ ... FixedIterationsStoppingCriterion(100), ... selector = random_selector) Note how, in order to restart the learning rocedure from fresh, the ``reset`` function was called. In this way the inferred model is initialized using randomly picked values. The inferred model is available through the ``model`` field. In order to get some information about its the performance is that of invoking the ``test`` function inherited from the ``Model`` class so as to get the mean approximation error, evaluated on all fed examples: :: >>> alg.model.test(and_sample) 0.0 As a final remark, it should be highlighted that these examples are shown for illustrative purpose. The suitable way of assessing a learnt model performance involves more complex techniques involving the use of a test set possibly coupled with a cross validation procedure (see function ``cross_validation`` in package ``yaplf.utility.validation``.) AUTHORS: - Dario Malchiodi (2010-02-22) """ IterativeAlgorithm.run(self, **kwargs) while self.stop_criterion.stop() == False: elem = self.sample_selector.next() answer = self.model.compute(elem.pattern) if type(answer) != type(()): answer = (answer,) # for i in range(len(self.sample[0].label)): # if answer[i] == 1 and elem.label[i] == 0: # self.model.weights[i] -= hstack((elem.pattern, # (-1 if self.threshold else 0))) # # if answer[i] == 0 and elem.label[i] == 1: # self.model.weights[i] += hstack((elem.pattern, # (-1 if self.threshold else 0))) temporary_weights = self.model.weights temporary_threshold = self.model.threshold for i in range(len(self.sample[0].label)): if answer[i] != elem.label[i]: temporary_weights[i] += [(elem.label[i] - answer[i]) * p for p in elem.pattern] temporary_threshold[i] += (elem.label[i] - answer[i]) * (-1 if self.threshold else 0) self.model.set_weights_and_threshold(temporary_weights, temporary_threshold) self.notify_observers()