|
| 1 | +# Daniel Shiffman |
| 2 | +# The Nature of Code, Fall 2006 |
| 3 | +# Neural Network |
| 4 | +# Class to describe the entire network |
| 5 | +# Arrays for input neurons, hidden neurons, and output neuron |
| 6 | +# Need to update this so that it would work with an array out outputs |
| 7 | +# Rather silly that I didn't do this initially |
| 8 | +# Also need to build in a "Layer" class so that there can easily |
| 9 | +# be more than one hidden layer |
| 10 | +class Network |
| 11 | + LEARNING_CONSTANT = 0.5 |
| 12 | + attr_reader :input, :hidden, :output |
| 13 | + # Only One output now to start!!! (i can do better, really. . .) |
| 14 | + # Constructor makes the entire network based on number of inputs & number of |
| 15 | + # neurons in hidden layer |
| 16 | + # Only One hidden layer!!! (fix this dood) |
| 17 | + def initialize(inputs, hidden_total) |
| 18 | + @input = (0..inputs).map { InputNeuron.new } # Got to add a bias input |
| 19 | + @hidden = (0..hidden_total).map { Neuron.new } # same as regular Neuron |
| 20 | + # Make bias neurons |
| 21 | + input[inputs] = Neuron.new(1) |
| 22 | + hidden[hidden_total] = Neuron.new(1) |
| 23 | + # Make output neuron |
| 24 | + @output = Neuron.new # same as regular Neuron |
| 25 | + # Connect input layer to hidden layer |
| 26 | + input.each do |input1| |
| 27 | + (0...hidden.length).each do |j| |
| 28 | + # Create the object and put it in both neurons |
| 29 | + c = Connection.new input1, hidden[j] |
| 30 | + input1.add_connection(c) |
| 31 | + hidden[j].add_connection(c) |
| 32 | + end |
| 33 | + end |
| 34 | + # Connect the hidden layer to the output neuron |
| 35 | + hidden.each do |hidden1| |
| 36 | + c = Connection.new(hidden1, output) |
| 37 | + hidden1.add_connection(c) |
| 38 | + output.add_connection(c) |
| 39 | + end |
| 40 | + end |
| 41 | + |
| 42 | + def feed_forward(input_vals) |
| 43 | + # Feed the input with an array of inputs |
| 44 | + input_vals.each_with_index do |val, i| |
| 45 | + input[i].input(val) |
| 46 | + end |
| 47 | + |
| 48 | + # Have the hidden layer calculate its output |
| 49 | + (0...hidden.length).each do |i| |
| 50 | + hidden[i].calc_output |
| 51 | + end |
| 52 | + |
| 53 | + # Calculate the output of the output neuron |
| 54 | + output.calc_output |
| 55 | + |
| 56 | + # Return output |
| 57 | + output.output |
| 58 | + end |
| 59 | + |
| 60 | + def train(inputs, answer) |
| 61 | + result = feed_forward(inputs) |
| 62 | + # This is where the error correction all starts |
| 63 | + # Derivative of sigmoid output function * diff between known and guess |
| 64 | + delta_output = result * (1 - result) * (answer - result) |
| 65 | + # BACKPROPOGATION |
| 66 | + # This is easier b/c we just have one output |
| 67 | + # Apply Delta to connections between hidden and output |
| 68 | + connections = output.connections |
| 69 | + connections.each do |c| |
| 70 | + neuron = c.from |
| 71 | + loutput = neuron.output |
| 72 | + delta_weight = loutput * delta_output |
| 73 | + c.adjust_weight(LEARNING_CONSTANT * delta_weight) |
| 74 | + end |
| 75 | + |
| 76 | + # ADJUST HIDDEN WEIGHTS |
| 77 | + hidden.each do |hidden1| |
| 78 | + connections = hidden1.connections |
| 79 | + sum = 0 |
| 80 | + # Sum output delta * hidden layer connections (just one output) |
| 81 | + connections.each do |c| |
| 82 | + # Is this a from hidden layer to next layer (output)? |
| 83 | + sum += c.weight * delta_output if c.from == hidden1 |
| 84 | + end |
| 85 | + # Then adjust the weights coming in based: |
| 86 | + # Above sum * derivative of sigmoid output function for hidden neurons |
| 87 | + connections.each do |c| |
| 88 | + # Is this a from previous layer (input) to hidden layer? |
| 89 | + next unless c.to == hidden1 |
| 90 | + loutput = hidden1.output |
| 91 | + delta_hidden = loutput * (1 - loutput) # Derivative of sigmoid(x) |
| 92 | + delta_hidden *= sum # Would sum for all outputs if more than one output |
| 93 | + neuron = c.from |
| 94 | + delta_weight = neuron.output * delta_hidden |
| 95 | + c.adjust_weight(LEARNING_CONSTANT * delta_weight) |
| 96 | + end |
| 97 | + end |
| 98 | + result |
| 99 | + end |
| 100 | +end |
0 commit comments