User:Ping/Python Perceptron

From Noisebridge
< User:Ping(Difference between revisions)
Jump to: navigation, search
Line 73: Line 73:
 
     rate *= 0.99
 
     rate *= 0.99
  
 +
</pre>
 +
 +
The version below has two classes: Perceptron (which produces a floating-point output) and BooleanPerceptron (which produces a Boolean output).
 +
 +
<pre>#!/usr/bin/env python
 +
 +
__author__ = 'Ka-Ping Yee <ping@zesty.ca>'
 +
 +
def dot_product(inputs, weights):
 +
    return sum(input*weight for input, weight in zip(inputs, weights))
 +
 +
class Perceptron:
 +
    def __init__(self, size):
 +
        """The 'size' parameter sets the number of inputs to this Perceptron."""
 +
        self.weights = [0.0]*size + [0.0]
 +
 +
    def __repr__(self):
 +
        """Display the internal weights of this Perceptron."""
 +
        weights = ', '.join('%.3g' % weight for weight in self.weights)
 +
        return '<%s %s>' % (self.__class__.__name__, weights)
 +
 +
    def evaluate(self, inputs):
 +
        """Evaluate this Perceptron with the given inputs, giving 0 or 1.
 +
        'inputs' should be a list of numbers, and the length of the list
 +
        should equal the 'size' used to construct this Perceptron."""
 +
        return dot_product(self.weights, inputs + [1])
 +
 +
    def adjust(self, inputs, rate):
 +
        """Adjust the weights of this Perceptron for the given inputs, using
 +
        the given training rate."""
 +
        for i, input in enumerate(inputs + [1]):
 +
            self.weights[i] += rate*input
 +
 +
    def train(self, inputs, expected_output, rate):
 +
        """Train this Perceptron for a single test case."""
 +
        output = self.evaluate(inputs)
 +
        self.adjust(inputs, rate*(expected_output - output))
 +
 +
    def train_all(self, training_set, rate):
 +
        """Train this Perceptron for all cases in the given training set."""
 +
        for inputs, expected_output in training_set:
 +
            self.train(inputs, expected_output, rate)
 +
 +
    def check_all(self, training_set):
 +
        """Check whether this Perceptron produces all the correct outputs."""
 +
        print self
 +
        failures = 0
 +
        for inputs, expected_output in training_set:
 +
            output = self.evaluate(inputs)
 +
            print '    %r -> %r (want %r)' % (inputs, output, expected_output)
 +
            if output != expected_output:
 +
                failures += 1
 +
        return not failures
 +
 +
class BooleanPerceptron(Perceptron):
 +
    def evaluate(self, inputs):
 +
        """Just like Perceptron.evaluate, but apply a threshold."""
 +
        return int(Perceptron.evaluate(self, inputs) > 0)
 +
 +
training_set = [
 +
    ([1, 0, 0], 1),
 +
    ([1, 0, 1], 1),
 +
    ([1, 1, 0], 1),
 +
    ([1, 1, 1], 0),
 +
    ([0, 1, 0], 1),
 +
    ([0, 0, 1], 1),
 +
    ([0, 1, 1], 1),
 +
    ([0, 0, 0], 1),
 +
]
 +
 +
perceptron = BooleanPerceptron(3)
 +
rate = 0.1
 +
while rate > 1e-9:
 +
    if perceptron.check_all(training_set):
 +
        print
 +
        print 'Success:', perceptron
 +
        break
 +
    perceptron.train_all(training_set, rate)
 +
    rate *= 0.9999
 
</pre>
 
</pre>

Revision as of 20:36, 18 March 2009

This Perceptron builds in a bias input (by internally appending an extra 1 to the inputs).

#!/usr/bin/env python

__author__ = 'Ka-Ping Yee <ping@zesty.ca>'

def dot_product(inputs, weights):
    return sum(input*weight for input, weight in zip(inputs, weights))

class Perceptron:
    def __init__(self, size):
        """The 'size' parameter sets the number of inputs to this Perceptron."""
        self.weights = [0.0]*size + [0.0]
        self.threshold = 0.0

    def __repr__(self):
        """Display the weights and threshold of this Perceptron."""
        weights = '[%s]' % (', '.join('%.3g' % w for w in self.weights))
        return '<weights=%s, threshold=%r>' % (weights, self.threshold)

    def evaluate(self, inputs):
        """Evaluate this Perceptron with the given inputs, giving 0 or 1.
        'inputs' should be a list of numbers, and the length of the list
        should equal the 'size' used to construct this Perceptron."""
        return int(dot_product(self.weights, inputs + [1]) > self.threshold)

    def adjust(self, inputs, rate):
        """Adjust the weights of this Perceptron for the given inputs, using
        the given training rate."""
        for i, input in enumerate(inputs + [1]):
            self.weights[i] += rate*input

    def train(self, inputs, expected_output, rate):
        """Train this Perceptron for a single test case."""
        output = self.evaluate(inputs)
        self.adjust(inputs, rate*(expected_output - output))

    def train_all(self, training_set, rate):
        """Train this Perceptron for all cases in the given training set."""
        for inputs, expected_output in training_set:
            self.train(inputs, expected_output, rate)

    def check_all(self, training_set):
        """Check whether this Perceptron produces all the correct outputs."""
        print self
        failures = 0
        for inputs, expected_output in training_set:
            output = self.evaluate(inputs)
            print '    %r -> %r (want %r)' % (inputs, output, expected_output)
            if output != expected_output:
                failures += 1
        return not failures

training_set = [
    ([1, 0, 0], 1),
    ([1, 0, 1], 1),
    ([1, 1, 0], 1),
    ([1, 1, 1], 0),
    ([0, 1, 0], 1),
    ([0, 0, 1], 1),
    ([0, 1, 1], 1),
    ([0, 0, 0], 1),
]

perceptron = Perceptron(3)
rate = 0.1
while rate > 1e-9:
    if perceptron.check_all(training_set):
        print
        print 'Success:', perceptron
        break
    perceptron.train_all(training_set, rate)
    rate *= 0.99

The version below has two classes: Perceptron (which produces a floating-point output) and BooleanPerceptron (which produces a Boolean output).

#!/usr/bin/env python

__author__ = 'Ka-Ping Yee <ping@zesty.ca>'

def dot_product(inputs, weights):
    return sum(input*weight for input, weight in zip(inputs, weights))

class Perceptron:
    def __init__(self, size):
        """The 'size' parameter sets the number of inputs to this Perceptron."""
        self.weights = [0.0]*size + [0.0]

    def __repr__(self):
        """Display the internal weights of this Perceptron."""
        weights = ', '.join('%.3g' % weight for weight in self.weights)
        return '<%s %s>' % (self.__class__.__name__, weights)

    def evaluate(self, inputs):
        """Evaluate this Perceptron with the given inputs, giving 0 or 1.
        'inputs' should be a list of numbers, and the length of the list
        should equal the 'size' used to construct this Perceptron."""
        return dot_product(self.weights, inputs + [1])

    def adjust(self, inputs, rate):
        """Adjust the weights of this Perceptron for the given inputs, using
        the given training rate."""
        for i, input in enumerate(inputs + [1]):
            self.weights[i] += rate*input

    def train(self, inputs, expected_output, rate):
        """Train this Perceptron for a single test case."""
        output = self.evaluate(inputs)
        self.adjust(inputs, rate*(expected_output - output))

    def train_all(self, training_set, rate):
        """Train this Perceptron for all cases in the given training set."""
        for inputs, expected_output in training_set:
            self.train(inputs, expected_output, rate)

    def check_all(self, training_set):
        """Check whether this Perceptron produces all the correct outputs."""
        print self
        failures = 0
        for inputs, expected_output in training_set:
            output = self.evaluate(inputs)
            print '    %r -> %r (want %r)' % (inputs, output, expected_output)
            if output != expected_output:
                failures += 1
        return not failures

class BooleanPerceptron(Perceptron):
    def evaluate(self, inputs):
        """Just like Perceptron.evaluate, but apply a threshold."""
        return int(Perceptron.evaluate(self, inputs) > 0)

training_set = [
    ([1, 0, 0], 1),
    ([1, 0, 1], 1),
    ([1, 1, 0], 1),
    ([1, 1, 1], 0),
    ([0, 1, 0], 1),
    ([0, 0, 1], 1),
    ([0, 1, 1], 1),
    ([0, 0, 0], 1),
]

perceptron = BooleanPerceptron(3)
rate = 0.1
while rate > 1e-9:
    if perceptron.check_all(training_set):
        print
        print 'Success:', perceptron
        break
    perceptron.train_all(training_set, rate)
    rate *= 0.9999
Personal tools