class CooCoo::Convolution::BoxLayer

Attributes

delta_accumulator[R]
height[R]
horizontal_step[R]
input_height[R]
input_width[R]
int_output_height[R]
int_output_width[R]
internal_layer[R]
vertical_step[R]
width[R]

Public Class Methods

from_hash(h, network = nil) click to toggle source
# 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
new(width, height, horizontal_step, vertical_step, internal_layer, input_width, input_height, int_output_width, int_output_height, update_weights_with = :average) click to toggle source
# 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

Public Instance Methods

==(other) click to toggle source
# 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_function() click to toggle source
# File lib/coo-coo/convolution.rb, line 35
def activation_function
  internal_layer.activation_function
end
adjust_weights!(deltas) click to toggle source
# 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) click to toggle source
# 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_area() { |grid_x, grid_y| ... } click to toggle source

private

# 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) click to toggle source
# 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) click to toggle source
# 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_span() click to toggle source
# File lib/coo-coo/convolution.rb, line 39
def horizontal_span
  @horizontal_span ||= (@width / @horizontal_step.to_f).ceil
end
neurons() click to toggle source
# File lib/coo-coo/convolution.rb, line 63
def neurons
  internal_layer.neurons
end
num_inputs() click to toggle source
# File lib/coo-coo/convolution.rb, line 47
def num_inputs
  @width * @height
end
output_height() click to toggle source
# File lib/coo-coo/convolution.rb, line 55
def output_height
  (vertical_span * int_output_height).to_i
end
output_width() click to toggle source
# File lib/coo-coo/convolution.rb, line 51
def output_width
  (horizontal_span * int_output_width).to_i
end
size() click to toggle source
# File lib/coo-coo/convolution.rb, line 59
def size
  output_height * output_width
end
slice_input(input, grid_x, grid_y) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# File lib/coo-coo/convolution.rb, line 110
def update_weights!(inputs, deltas)
  adjust_weights!(*weight_deltas(inputs, deltas))
end
vertical_span() click to toggle source
# File lib/coo-coo/convolution.rb, line 43
def vertical_span
  @vertical_span ||= (@height / @vertical_step.to_f).ceil
end
weight_deltas(inputs, deltas) click to toggle source
# 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