class CooCoo::Network

Attributes

activation_function[R]
age[R]
command[RW]
comments[RW]

Public Class Methods

from_a(layers) click to toggle source
# File lib/coo-coo/network.rb, line 212
def from_a(layers)
  self.new().update_from_a!(layers)
end
from_hash(h) click to toggle source
# File lib/coo-coo/network.rb, line 216
def from_hash(h)
  self.new.update_from_hash!(h)
end
load(path) click to toggle source
# File lib/coo-coo/network.rb, line 220
def load(path)
  self.new().load!(path)
end
new() { |self| ... } click to toggle source
# File lib/coo-coo/network.rb, line 15
def initialize
  @layers = Array.new
  @age = 0
  @command = [ $0 ] + ARGV
  yield(self) if block_given?
end

Public Instance Methods

adjust_weights!(deltas) click to toggle source
# File lib/coo-coo/network.rb, line 140
def adjust_weights!(deltas)
  @layers.each_with_index do |layer, i|
    layer.adjust_weights!(deltas[i])
  end

  @age += 1
  self
end
backprop(inputs, outputs, errors, hidden_state = nil) click to toggle source
# File lib/coo-coo/network.rb, line 109
def backprop(inputs, outputs, errors, hidden_state = nil)
  hidden_state ||= Hash.new
  d = @layers.reverse_each.each_with_index.inject([]) do |acc, (layer, i)|
    input = if i < (@layers.size - 1)
              outputs[@layers.size - i - 2]
            else
              prep_input(inputs) # TODO condition prep_input
            end
    #CooCoo.debug("#{self.class.name}.#{__method__}\t#{i} #{@layers.size - i - 1}\t#{input.size}\t#{outputs.size}")
    deltas, hidden_state = layer.backprop(input,
                                          outputs[@layers.size - i - 1],
                                          errors,
                                          hidden_state)
    errors = layer.transfer_error(deltas)
    acc.unshift(deltas)
  end

  return Sequence[d], hidden_state
end
final_output(outputs) click to toggle source
# File lib/coo-coo/network.rb, line 73
def final_output(outputs)
  outputs.last
end
forward(input, hidden_state = nil, flattened = false, processed = false) click to toggle source
# File lib/coo-coo/network.rb, line 77
def forward(input, hidden_state = nil, flattened = false, processed = false)
  unless flattened || input.kind_of?(CooCoo::Vector)
    input = CooCoo::Vector[input.to_a.flatten, num_inputs]
  end

  hidden_state ||= Hash.new

  output = if processed
             input
           else
             prep_input(input)
           end
  
  outputs = @layers.each_with_index.inject([]) do |acc, (layer, i)|
    #debug("Layer: #{i} #{layer.num_inputs} #{layer.size}")
    #debug("Input: #{input}")
    #debug("Weights: #{layer.neurons[0].weights}")
    output, hidden_state = layer.forward(output, hidden_state)
    acc << output
    #debug("Output: #{input}")
  end

  return outputs, hidden_state
end
layer(new_layer) click to toggle source
# File lib/coo-coo/network.rb, line 42
def layer(new_layer)
  @layers << new_layer
  self
end
layer_index(layer) click to toggle source
# File lib/coo-coo/network.rb, line 38
def layer_index(layer)
  @layers.find_index { |l| l.eql?(layer) }
end
layers() click to toggle source
# File lib/coo-coo/network.rb, line 34
def layers
  @layers
end
learn(input, expecting, rate, cost_function = CostFunctions::MeanSquare, hidden_state = nil) click to toggle source
# File lib/coo-coo/network.rb, line 162
def learn(input, expecting, rate, cost_function = CostFunctions::MeanSquare, hidden_state = nil)
  hidden_state ||= Hash.new
  output, hidden_state = forward(input, hidden_state)
  cost = cost_function.derivative(prep_input(expecting), output.last)
  deltas, hidden_state = backprop(input, output, cost, hidden_state)
  update_weights!(input, output, deltas * rate)
  return self, hidden_state
rescue
  CooCoo.debug("Network#learn caught #{$!}", input, expecting)
  raise
end
load!(path) click to toggle source
# File lib/coo-coo/network.rb, line 180
def load!(path)
  yaml = YAML.load(File.read(path))
  raise RuntimeError.new("Invalid YAML definition in #{path}") if yaml.nil?
    
  update_from_hash!(yaml)

  self
end
num_inputs() click to toggle source
# File lib/coo-coo/network.rb, line 22
def num_inputs
  @layers.first.num_inputs
end
num_layers() click to toggle source
# File lib/coo-coo/network.rb, line 30
def num_layers
  @layers.size
end
num_outputs() click to toggle source
# File lib/coo-coo/network.rb, line 26
def num_outputs
  @layers.last.size
end
output_activation_function() click to toggle source
# File lib/coo-coo/network.rb, line 56
def output_activation_function
  unless @output_activation_function
    layer = @layers.reverse.find { |l| l.activation_function }
    @output_activation_function = layer.activation_function
  end

  @output_activation_function
end
predict(input, hidden_state = nil, flattened = false, processed = false) click to toggle source
# File lib/coo-coo/network.rb, line 102
def predict(input, hidden_state = nil, flattened = false, processed = false)
  hidden_state ||= Hash.new
  outputs, hidden_state = forward(input, hidden_state, flattened, processed)
  out = final_output(outputs)
  return out, hidden_state
end
prep_input(input) click to toggle source
# File lib/coo-coo/network.rb, line 65
def prep_input(input)
  activation_function.prep_input(input)
end
prep_output_target(target) click to toggle source
# File lib/coo-coo/network.rb, line 69
def prep_output_target(target)
  output_activation_function.prep_output_target(target)
end
save(path) click to toggle source
# File lib/coo-coo/network.rb, line 174
def save(path)
  File.write_to(path) do |f|
    f.write(to_hash.to_yaml)
  end
end
to_hash() click to toggle source
# File lib/coo-coo/network.rb, line 203
def to_hash
  { age: @age,
    command: @command,
    comments: @comments,
    layers: @layers.collect { |l| l.to_hash(self) }
  }
end
transfer_errors(deltas) click to toggle source
# File lib/coo-coo/network.rb, line 129
def transfer_errors(deltas)
  @layers.zip(deltas).collect do |layer, delta|
    layer.transfer_error(delta)
  end
end
update_from_hash!(h) click to toggle source
# File lib/coo-coo/network.rb, line 189
def update_from_hash!(h)
  @layers = Array.new
  
  h[:layers].each do |layer_hash|
    @layers << CooCoo::LayerFactory.from_hash(layer_hash, self)
  end

  @age = h.fetch(:age, 0)
  @command = h.fetch(:command, nil)
  @comments = h.fetch(:comments) { Array.new }

  self
end
update_weights!(input, outputs, deltas) click to toggle source
# File lib/coo-coo/network.rb, line 135
def update_weights!(input, outputs, deltas)
  adjust_weights!(weight_deltas(input, outputs, deltas))
  self
end
weight_deltas(input, outputs, deltas) click to toggle source
# File lib/coo-coo/network.rb, line 149
def weight_deltas(input, outputs, deltas)
  d = @layers.each_with_index.collect do |layer, i|
    inputs = if i != 0
               outputs[i - 1]
             else
               prep_input(input)
             end
    layer.weight_deltas(inputs, deltas[i])
  end

  d
end