class RANN::Network
Constants
- UnconnectedNetworkError
Public Class Methods
new(connections = [])
click to toggle source
# File lib/rann/network.rb, line 17 def initialize connections = [] @connections = connections @neurons = connections.flat_map(&:neurons).uniq @input_neurons = @neurons.select &:input? @output_neurons = @neurons.select &:output? @hidden_neurons = @neurons - @input_neurons - @output_neurons end
Public Instance Methods
add(*features)
click to toggle source
# File lib/rann/network.rb, line 118 def add *features features.each do |feature| case feature when Neuron case feature.type when :input @input_neurons << feature when :output @output_neurons << feature else @hidden_neurons << feature end @neurons << feature when Connection @connections << feature when Network add *feature.neurons add *feature.connections end end end
connections_from(neuron)
click to toggle source
# File lib/rann/network.rb, line 112 def connections_from neuron @connections_from = {} unless defined? @connections_from @connections_from[neuron] ||= connections.select{ |con| con.input_neuron == neuron } end
connections_to(neuron)
click to toggle source
# File lib/rann/network.rb, line 106 def connections_to neuron @connections_to = {} unless defined? @connections_to @connections_to[neuron] ||= connections.select{ |con| con.output_neuron == neuron } end
dump_weights()
click to toggle source
# File lib/rann/network.rb, line 91 def dump_weights File.write "nn_weights_dump_#{DateTime.now.strftime('%Y-%m-%d-%H-%M-%S')}.yml", params.to_yaml end
evaluate(input)
click to toggle source
# File lib/rann/network.rb, line 35 def evaluate input input_neurons.each.with_index do |neuron, i| neuron.value = input[i] end # use some proper graph traversal, rather than this crude blanketing? # would probably be easier to detect circular dependency this way too? begin i = 0 until connections.select(&:enabled?).all? &:processed? i += 1 connections.each do |connection| next if !connection.enabled? connection.process end raise UnconnectedNetworkError if i > 5_000 end rescue UnconnectedNetworkError visualise raise end outputs end
impose(weights)
click to toggle source
# File lib/rann/network.rb, line 25 def impose weights connections.each.with_index do |c, i| c.weight = weights[i] end end
init_normalised!()
click to toggle source
# File lib/rann/network.rb, line 168 def init_normalised! connections.each do |c| next if c.locked? out_cons = c.output_neuron.connection_count.to_d from = -1.to_d / out_cons.sqrt(0) to = 1.to_d / out_cons.sqrt(0) c.weight = (to - from) * rand.to_d + from end true end
Also aliased as: init_normalized!
neurons_with_no_outgoing_connections()
click to toggle source
# File lib/rann/network.rb, line 190 def neurons_with_no_outgoing_connections return @no_outgoing if defined? @no_outgoing neurons.select do |n| connections_from(n).none? end end
outputs()
click to toggle source
# File lib/rann/network.rb, line 95 def outputs output_neurons.map &:value end
params()
click to toggle source
# File lib/rann/network.rb, line 31 def params connections.map(&:weight) end
recalculate_neuron_connection_counts!()
click to toggle source
# File lib/rann/network.rb, line 182 def recalculate_neuron_connection_counts! neurons.each do |neuron| neuron.connection_count = connections.count{ |c| c.output_neuron == neuron } end true end
remove(*features)
click to toggle source
# File lib/rann/network.rb, line 141 def remove *features features.each do |feature| case feature when Neuron case feature.type when :input raise "trying to remove an input neuron ..." when :output raise "trying to remove an output neuron ..." else @hidden_neurons.delete feature end @neurons.delete feature when Connection @connections.delete feature end end end
reset!()
click to toggle source
# File lib/rann/network.rb, line 161 def reset! state.tap do neurons.each{ |neuron| neuron.reset! } connections.each{ |connection| connection.reset! } end end
state()
click to toggle source
# File lib/rann/network.rb, line 99 def state { values: neurons.each.with_object({}){ |n, s| s[n.id] = n.value }, intermediates: neurons.select{ |n| n.is_a? ProductNeuron }.each.with_object({}){ |n, s| s[n.id] = n.intermediate } } end
visualise()
click to toggle source
# File lib/rann/network.rb, line 61 def visualise # Create a new graph g = GraphViz.new(:G, type: :digraph) # Create nodes missing_nodes = connections.each.with_object([]) do |c, o| o << c.output_neuron unless neurons.include? c.output_neuron o << c.input_neuron unless neurons.include? c.input_neuron end graph_nodes = neurons.each.with_object({}) do |n, h| h[n] = g.add_nodes("#{n.name}: #{n.value&.to_f&.round(5)}") end # Create edges between the nodes connections.each do |c| g.add_edges( graph_nodes[c.input_neuron], graph_nodes[c.output_neuron], color: c.processed? ? "#ff0000" : "#000000", label: c.weight.to_f.round(5) ) end # Generate output image g.output png: "nnet.png" `open nnet.png` end