Permalink
Fetching contributors…
Cannot retrieve contributors at this time
147 lines (121 sloc) 3.36 KB
class Random
public :rand
end
class Synapse
attr_accessor :weight, :prev_weight
attr_accessor :source_neuron, :dest_neuron
def initialize(source_neuron, dest_neuron, prng)
self.source_neuron = source_neuron
self.dest_neuron = dest_neuron
self.prev_weight = self.weight = prng.rand * 2 - 1
end
end
class Neuron
LEARNING_RATE = 1.0
MOMENTUM = 0.3
attr_accessor :synapses_in, :synapses_out
attr_accessor :threshold, :prev_threshold, :error
attr_accessor :output
def initialize(prng)
self.prev_threshold = self.threshold = prng.rand * 2 - 1
self.synapses_in = []
self.synapses_out = []
end
def calculate_output
activation = synapses_in.inject(0.0) do |sum, synapse|
sum + synapse.weight * synapse.source_neuron.output
end
activation -= threshold
self.output = 1.0 / (1.0 + Math.exp(-activation))
end
def derivative
output * (1 - output)
end
def output_train(rate, target)
self.error = (target - output) * derivative
update_weights(rate)
end
def hidden_train(rate)
self.error = synapses_out.inject(0.0) do |sum, synapse|
sum + synapse.prev_weight * synapse.dest_neuron.error
end * derivative
update_weights(rate)
end
def update_weights(rate)
synapses_in.each do |synapse|
temp_weight = synapse.weight
synapse.weight += (rate * LEARNING_RATE * error * synapse.source_neuron.output) + (MOMENTUM * ( synapse.weight - synapse.prev_weight))
synapse.prev_weight = temp_weight
end
temp_threshold = threshold
self.threshold += (rate * LEARNING_RATE * error * -1) + (MOMENTUM * (threshold - prev_threshold))
self.prev_threshold = temp_threshold
end
end
class NeuralNetwork
attr_accessor :prng
def initialize(inputs, hidden, outputs)
self.prng = Random.new
@input_layer = (1..inputs).map do
Neuron.new(prng)
end
@hidden_layer = (1..hidden).map do
Neuron.new(prng)
end
@output_layer = (1..outputs).map do
Neuron.new(prng)
end
@input_layer.product(@hidden_layer).each do |source, dest|
synapse = Synapse.new(source, dest, prng)
source.synapses_out << synapse
dest.synapses_in << synapse
end
@hidden_layer.product(@output_layer).each do |source, dest|
synapse = Synapse.new(source, dest, prng)
source.synapses_out << synapse
dest.synapses_in << synapse
end
end
def train(inputs, targets)
feed_forward(inputs)
@output_layer.zip(targets).each do |neuron, target|
neuron.output_train(0.3, target)
end
@hidden_layer.each do |neuron|
neuron.hidden_train(0.3)
end
end
def feed_forward(inputs)
@input_layer.zip(inputs).each do |neuron, input|
neuron.output = input
end
@hidden_layer.each do|neuron|
neuron.calculate_output
end
@output_layer.each do |neuron|
neuron.calculate_output
end
end
def current_outputs
@output_layer.map do |neuron|
neuron.output
end
end
end
5.times do
xor = NeuralNetwork.new(2, 10, 1)
10000.times do
xor.train([0, 0], [0])
xor.train([1, 0], [1])
xor.train([0, 1], [1])
xor.train([1, 1], [0])
end
xor.feed_forward([0, 0])
puts xor.current_outputs
xor.feed_forward([0, 1])
puts xor.current_outputs
xor.feed_forward([1, 0])
puts xor.current_outputs
xor.feed_forward([1, 1])
puts xor.current_outputs
end