Skip to content

Instantly share code, notes, and snippets.

@macournoyer
Last active January 9, 2023 15:12
Show Gist options
  • Save macournoyer/620a8ba4a2ecd6d6feaf to your computer and use it in GitHub Desktop.
Save macournoyer/620a8ba4a2ecd6d6feaf to your computer and use it in GitHub Desktop.

Revisions

  1. macournoyer renamed this gist Dec 16, 2015. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. macournoyer revised this gist Dec 16, 2015. 1 changed file with 11 additions and 0 deletions.
    11 changes: 11 additions & 0 deletions output.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    $ python xor.py
    Training:
    Epoch 0 MSE: 1.765
    Epoch 100 MSE: 0.015
    Epoch 200 MSE: 0.005
    * Target MSE reached *
    Evaluating:
    1 XOR 0 = 1 ( 0.904) Error: 0.096
    0 XOR 1 = 1 ( 0.908) Error: 0.092
    1 XOR 1 = 0 (-0.008) Error: 0.008
    0 XOR 0 = 0 ( 0.000) Error: 0.000
  3. macournoyer created this gist Dec 16, 2015.
    49 changes: 49 additions & 0 deletions nn.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,49 @@
    import numpy as np

    # Activation functions
    def tanh(x):
    return np.tanh(x)

    # Derivative of tanh from its output
    def dtanh(y):
    return 1 - y ** 2

    # The neural network framework
    class Layer:
    def __init__(self, num_inputs, num_outputs):
    # Init all weights between [-1 .. 1].
    # Each input is connected to all outputs.
    # One line per input and one column per output.
    self.weights = np.random.uniform(-1, 1, (num_inputs, num_outputs))

    def forward(self, input):
    self.output = tanh(input.dot(self.weights))
    return self.output

    def computeGradient(self, error):
    self.delta = error * dtanh(self.output)
    # Returns the gradient
    return self.delta.dot(self.weights.T)

    def updateWeights(self, input, learning_rate):
    self.weights += input.T.dot(self.delta) * learning_rate

    class Network:
    def __init__(self, layers):
    self.layers = layers

    def forward(self, input):
    output = input
    for layer in self.layers:
    output = layer.forward(output)
    return output

    def backprop(self, input, error, learning_rate):
    # Compute deltas at each layer starting from the last one
    for layer in reversed(self.layers):
    error = layer.computeGradient(error)

    # Update the weights
    for layer in self.layers:
    layer.updateWeights(input, learning_rate)
    input = layer.output
    67 changes: 67 additions & 0 deletions xor.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,67 @@
    import numpy as np
    import nn

    # Training examples
    examples = [
    # _ XOR _ = _
    [ np.array([[ 0, 0 ]]), np.array([[ 0 ]]) ],
    [ np.array([[ 0, 1 ]]), np.array([[ 1 ]]) ],
    [ np.array([[ 1, 0 ]]), np.array([[ 1 ]]) ],
    [ np.array([[ 1, 1 ]]), np.array([[ 0 ]]) ]
    ]


    # Seed random generator to get consistent results
    np.random.seed(0)


    # Build the model
    num_inputs = 2
    num_hidden = 20 # nodes in hidden layer
    num_output = 1
    network = nn.Network([
    nn.Layer(num_inputs, num_hidden),
    nn.Layer(num_hidden, num_output)
    ])


    # Train the model
    print("Training:")
    learning_rate = 0.1
    target_mse = 0.01

    for epoch in range(500):
    errors = []

    for input, target in examples:
    # Forward
    output = network.forward(input)

    # Compute the error
    error = target - output
    errors.append(error)

    # Back-propagate the error
    network.backprop(input, error, learning_rate)

    # Compute the Mean Squared Error of all examples each 100 epoch
    if epoch % 100 == 0:
    mse = (np.array(errors) ** 2).mean()
    print(" Epoch %3d MSE: %.3f" % (epoch, mse))
    if mse <= target_mse:
    print(" * Target MSE reached *")
    break


    # Evaluate the model
    def eval(x, y):
    output = network.forward(x)
    normalized = int(round(output[0]))
    error = y - output[0]
    return "%d (% .3f) Error: %.3f" % (normalized, output[0], error)

    print("Evaluating:")
    print(" 1 XOR 0 = " + eval(np.array([1, 0]), 1))
    print(" 0 XOR 1 = " + eval(np.array([0, 1]), 1))
    print(" 1 XOR 1 = " + eval(np.array([1, 1]), 0))
    print(" 0 XOR 0 = " + eval(np.array([0, 0]), 0))