Class: Brainy::Network

Inherits:
Object
  • Object
show all
Defined in:
lib/brainy/network.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input_count, hidden_count, output_count, options = {}) ⇒ Network



5
6
7
8
9
10
11
12
13
14
15
16
17
# File 'lib/brainy/network.rb', line 5

def initialize(input_count, hidden_count, output_count, options = {})
  options = default_options.update(options)
  @learning_rate = options[:learning_rate]
  @momentum = options[:momentum]
  @activate = options[:activate]
  @activate_prime = options[:activate_prime]
  @weight_init = options[:weight_init]
  @layers = [
      JMatrix.build(hidden_count, input_count + 1) { @weight_init.call },
      JMatrix.build(output_count, hidden_count + 1) { @weight_init.call }
  ]
  @last_changes = []
end

Instance Attribute Details

#layersObject

Returns the value of attribute layers.



3
4
5
# File 'lib/brainy/network.rb', line 3

def layers
  @layers
end

Class Method Details

.from_serialized(dump, options = {}) ⇒ Object



73
74
75
76
77
78
# File 'lib/brainy/network.rb', line 73

def self.from_serialized(dump, options = {})
  layer_values = YAML.load(dump.class == File ? dump : File.open(dump))[:layers]
  net = Network.new(1, 1, 1, options)
  net.layers = layer_values.map { |vals| JMatrix.new(vals) }
  net
end

Instance Method Details

#default_optionsObject



19
20
21
22
23
24
25
26
27
# File 'lib/brainy/network.rb', line 19

def default_options
  {
      learning_rate: 0.25,
      momentum: 0.9,
      activate: lambda { |x| 1 / (1 + Math.exp(-1 * x)) },
      activate_prime: lambda { |x| x * (1 - x) },
      weight_init: lambda { Gaussian.next * 0.1 }
  }
end

#evaluate(inputs) ⇒ Object



29
30
31
32
33
# File 'lib/brainy/network.rb', line 29

def evaluate(inputs)
  @layers.reduce(inputs) do |input, layer|
    (layer * JMatrix.new(input.to_a + [1.0])).map(&@activate)
  end
end

#get_hidden_deltas(hidden_outs, output_nodes, output_deltas) ⇒ Object



55
56
57
58
59
60
61
# File 'lib/brainy/network.rb', line 55

def get_hidden_deltas(hidden_outs, output_nodes, output_deltas)
  hidden_outs.to_a.slice(0...-1).each_with_index.map do |out, index|
    output_nodes.row_vectors.zip(output_deltas)
        .map { |weights, delta| weights[index] * delta }
        .reduce(:+) * @activate_prime.call(out)
  end
end

#get_output_deltas(expected, output) ⇒ Object



49
50
51
52
53
# File 'lib/brainy/network.rb', line 49

def get_output_deltas(expected, output)
  expected.zip(output.to_a).map do |expect, out|
    (out - expect) * @activate_prime.call(out)
  end
end

#get_weight_change(inputs, deltas) ⇒ Object



63
64
65
66
67
# File 'lib/brainy/network.rb', line 63

def get_weight_change(inputs, deltas)
  JMatrix.build(deltas.count, inputs.to_a.count) do |row, col|
    @learning_rate * deltas[row] * inputs[col]
  end
end

#serializeObject



69
70
71
# File 'lib/brainy/network.rb', line 69

def serialize
  YAML.dump({ layers: layers.map(&:to_a) })
end

#train!(inputs, expected) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/brainy/network.rb', line 35

def train!(inputs, expected)
  inputs = JMatrix.new(inputs + [1.0])
  hidden_outs = JMatrix.new((@layers.first * inputs).map(&@activate).to_a + [1.0])
  output_outs = (@layers.last * hidden_outs).map(&@activate)
  output_deltas = get_output_deltas(expected, output_outs)
  hidden_deltas = get_hidden_deltas(hidden_outs, @layers.last, output_deltas)
  changes = [get_weight_change(inputs, hidden_deltas), get_weight_change(hidden_outs, output_deltas)]
  @layers.length.times do |idx|
    @layers[idx] -= changes[idx]
    @layers[idx] -= (@last_changes[idx] * @momentum) unless @last_changes[idx].nil?
  end
  @last_changes = changes
end