Class: CooCoo::Convolution::BoxLayer

Inherits:
Object
  • Object
show all
Defined in:
lib/coo-coo/convolution.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(width, height, horizontal_step, vertical_step, internal_layer, input_width, input_height, int_output_width, int_output_height, update_weights_with = :average) ⇒ BoxLayer

Returns a new instance of BoxLayer.

Raises:

  • (ArgumentError)


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/coo-coo/convolution.rb', line 19

def initialize(width, height, horizontal_step, vertical_step, internal_layer, input_width, input_height, int_output_width, int_output_height, update_weights_with = :average)
  @internal_layer = internal_layer
  @width = width
  @height = height
  @horizontal_step = horizontal_step
  @vertical_step = vertical_step
  @input_width = input_width
  @input_height = input_height
  raise ArgumentError.new("Input size mismatch: #{input_width * input_height} is not #{internal_layer.num_inputs}") if internal_layer.num_inputs != (input_width * input_height)
  @int_output_width = int_output_width
  @int_output_height = int_output_height
  raise ArgumentError.new("Input size mismatch: #{int_output_width * int_output_height} is not #{internal_layer.size}") if internal_layer.size != (int_output_width * int_output_height)
  @delta_accumulator = delta_accumulator || :average
  raise ArgumentError.new("Weights delta accumulator can only be averaged or summed") unless [ :average, :sum ].include?(@delta_accumulator)
end

Instance Attribute Details

#delta_accumulatorObject (readonly)

Returns the value of attribute delta_accumulator.



17
18
19
# File 'lib/coo-coo/convolution.rb', line 17

def delta_accumulator
  @delta_accumulator
end

#heightObject (readonly)

Returns the value of attribute height.



9
10
11
# File 'lib/coo-coo/convolution.rb', line 9

def height
  @height
end

#horizontal_stepObject (readonly)

Returns the value of attribute horizontal_step.



10
11
12
# File 'lib/coo-coo/convolution.rb', line 10

def horizontal_step
  @horizontal_step
end

#input_heightObject (readonly)

Returns the value of attribute input_height.



13
14
15
# File 'lib/coo-coo/convolution.rb', line 13

def input_height
  @input_height
end

#input_widthObject (readonly)

Returns the value of attribute input_width.



12
13
14
# File 'lib/coo-coo/convolution.rb', line 12

def input_width
  @input_width
end

#int_output_heightObject (readonly)

Returns the value of attribute int_output_height.



15
16
17
# File 'lib/coo-coo/convolution.rb', line 15

def int_output_height
  @int_output_height
end

#int_output_widthObject (readonly)

Returns the value of attribute int_output_width.



14
15
16
# File 'lib/coo-coo/convolution.rb', line 14

def int_output_width
  @int_output_width
end

#internal_layerObject (readonly)

Returns the value of attribute internal_layer.



16
17
18
# File 'lib/coo-coo/convolution.rb', line 16

def internal_layer
  @internal_layer
end

#vertical_stepObject (readonly)

Returns the value of attribute vertical_step.



11
12
13
# File 'lib/coo-coo/convolution.rb', line 11

def vertical_step
  @vertical_step
end

#widthObject (readonly)

Returns the value of attribute width.



8
9
10
# File 'lib/coo-coo/convolution.rb', line 8

def width
  @width
end

Class Method Details

.from_hash(h, network = nil) ⇒ Object



165
166
167
168
169
170
171
172
# File 'lib/coo-coo/convolution.rb', line 165

def self.from_hash(h, network = nil)
  self.new(h.fetch(:width), h.fetch(:height),
           h.fetch(:horizontal_step), h.fetch(:vertical_step),
           LayerFactory.from_hash(h.fetch(:internal_layer)),
           h.fetch(:input_width), h.fetch(:input_height),
           h.fetch(:int_output_width), h.fetch(:int_output_height),
           h.fetch(:delta_accumulator, :average))
end

Instance Method Details

#==(other) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/coo-coo/convolution.rb', line 136

def ==(other)
  other.kind_of?(self.class) &&
    width == other.width &&
    height == other.height &&
    horizontal_step == other.horizontal_step &&
    vertical_step == other.vertical_step &&
    input_width == other.input_width &&
    input_height == other.input_height &&
    int_output_width == other.int_output_width &&
    int_output_height == other.int_output_height &&
    internal_layer == other.internal_layer &&
    delta_accumulator == other.delta_accumulator
end

#activation_functionObject



35
36
37
# File 'lib/coo-coo/convolution.rb', line 35

def activation_function
  internal_layer.activation_function
end

#adjust_weights!(deltas) ⇒ Object



114
115
116
117
# File 'lib/coo-coo/convolution.rb', line 114

def adjust_weights!(deltas)
  @internal_layer.adjust_weights!(deltas)
  self
end

#backprop(input, output, errors, hidden_state) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
# File 'lib/coo-coo/convolution.rb', line 92

def backprop(input, output, errors, hidden_state)
  hs = hidden_state[self] || Array.new
  deltas = each_area do |grid_x, grid_y|
    hs_index = grid_y * horizontal_span + grid_x
    d, layer_hs = @internal_layer.backprop(slice_input(input, grid_x, grid_y), slice_output(output, grid_x, grid_y), slice_output(errors, grid_x, grid_y), hs[hs_index])
    hs[hs_index] = layer_hs
    d
  end
  hidden_state[self] = hs
  [ Sequence[deltas.collect { |d| Sequence[d] }], hidden_state ]
end

#each_areaObject

private



176
177
178
179
180
181
182
183
184
# File 'lib/coo-coo/convolution.rb', line 176

def each_area
  return to_enum(:each_area) unless block_given?

  vertical_span.to_i.times.collect do |grid_y|
    horizontal_span.to_i.times.collect do |grid_x|
      yield(grid_x, grid_y)
    end
  end
end

#flatten_areas(outputs, w, h, inner_width) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/coo-coo/convolution.rb', line 67

def flatten_areas(outputs, w, h, inner_width)
  out = CooCoo::Vector.new(w * h)
  
  each_area do |grid_x, grid_y|
    area_output = outputs[grid_y][grid_x]
    gx = grid_x * w / horizontal_span.to_f
    gy = grid_y * h / vertical_span.to_f
    out.set2d!(w, area_output, inner_width, gx, gy)
  end

  out
end

#forward(input, hidden_state) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
# File 'lib/coo-coo/convolution.rb', line 80

def forward(input, hidden_state)
  hs = hidden_state[self] || Array.new
  outputs = each_area do |grid_x, grid_y|
    hs_index = (grid_y * horizontal_span + grid_x).to_i
    output, layer_hs = @internal_layer.forward(slice_input(input, grid_x, grid_y), hs[hs_index])
    hs[hs_index] = layer_hs
    output
  end
  hidden_state[self] = hs
  [ flatten_areas(outputs, horizontal_span * int_output_width, vertical_span * int_output_height, int_output_width), hidden_state ]
end

#horizontal_spanObject



39
40
41
# File 'lib/coo-coo/convolution.rb', line 39

def horizontal_span
  @horizontal_span ||= (@width / @horizontal_step.to_f).ceil
end

#neuronsObject



63
64
65
# File 'lib/coo-coo/convolution.rb', line 63

def neurons
  internal_layer.neurons
end

#num_inputsObject



47
48
49
# File 'lib/coo-coo/convolution.rb', line 47

def num_inputs
  @width * @height
end

#output_heightObject



55
56
57
# File 'lib/coo-coo/convolution.rb', line 55

def output_height
  (vertical_span * int_output_height).to_i
end

#output_widthObject



51
52
53
# File 'lib/coo-coo/convolution.rb', line 51

def output_width
  (horizontal_span * int_output_width).to_i
end

#sizeObject



59
60
61
# File 'lib/coo-coo/convolution.rb', line 59

def size
  output_height * output_width
end

#slice_input(input, grid_x, grid_y) ⇒ Object



186
187
188
189
190
191
192
193
194
# File 'lib/coo-coo/convolution.rb', line 186

def slice_input(input, grid_x, grid_y)
  origin_x = grid_x * @horizontal_step
  origin_y = grid_y * @vertical_step
  input.slice_2d(@width,
                 @height,
                 origin_x, origin_y,
                 @input_width, @input_height,
                 0.0)
end

#slice_output(output, grid_x, grid_y) ⇒ Object



196
197
198
199
200
201
202
203
204
# File 'lib/coo-coo/convolution.rb', line 196

def slice_output(output, grid_x, grid_y)
  origin_x = grid_x * @int_output_width
  origin_y = grid_y * @int_output_height
  output.slice_2d((horizontal_span * @int_output_width).to_i,
                  (vertical_span * @int_output_height).to_i,
                  origin_x, origin_y,
                  @int_output_width, @int_output_height,
                  0.0)
end

#to_hash(network = nil) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/coo-coo/convolution.rb', line 150

def to_hash(network = nil)
  { type: self.class.to_s,
    width: @width,
    height: @height,
    horizontal_step: @horizontal_step,
    vertical_step: @vertical_step,
    input_width: @input_width,
    input_height: @input_height,
    int_output_width: @int_output_width,
    int_output_height: @int_output_height,
    delta_accumulator: @delta_accumulator,
    internal_layer: @internal_layer.to_hash(network)
  }
end

#transfer_error(deltas) ⇒ Object



104
105
106
107
108
# File 'lib/coo-coo/convolution.rb', line 104

def transfer_error(deltas)
  flatten_areas(each_area do |grid_x, grid_y|
                  @internal_layer.transfer_error(deltas[grid_y][grid_x]).to_a
                end, width, height, input_width)
end

#update_weights!(inputs, deltas) ⇒ Object



110
111
112
# File 'lib/coo-coo/convolution.rb', line 110

def update_weights!(inputs, deltas)
  adjust_weights!(*weight_deltas(inputs, deltas))
end

#vertical_spanObject



43
44
45
# File 'lib/coo-coo/convolution.rb', line 43

def vertical_span
  @vertical_span ||= (@height / @vertical_step.to_f).ceil
end

#weight_deltas(inputs, deltas) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/coo-coo/convolution.rb', line 119

def weight_deltas(inputs, deltas)
  #rate = rate / (@horizontal_span * @vertical_span).to_f
  change = []
  wd = []

  d = []
  each_area do |grid_x, grid_y|
    hs_index = grid_y * horizontal_span + grid_x
    delta, hs = @internal_layer.
      weight_deltas(slice_input(inputs, grid_x, grid_y),
                    deltas[grid_y][grid_x])
    d << delta
  end

  Sequence[d].send(@delta_accumulator)
end