lib/dnn/core/layers.rb in ruby-dnn-0.2.2 vs lib/dnn/core/layers.rb in ruby-dnn-0.3.0

- old
+ new

@@ -1,11 +1,11 @@ module DNN module Layers #Super class of all optimizer classes. class Layer - include Numo + include Xumo def initialize @built = false end @@ -210,64 +210,63 @@ j_end = img.shape[1] - (pad[0] / 2.0).round img[true, j_begin...j_end, i_begin...i_end, true] end def out_size(prev_w, prev_h, fil_w, fil_h, strides) - out_w = (prev_w - fil_w) / strides[1] + 1 - out_h = (prev_h - fil_h) / strides[0] + 1 + out_w = (prev_w - fil_w) / strides[0] + 1 + out_h = (prev_h - fil_h) / strides[1] + 1 [out_w, out_h] end end class Conv2D < HasParamLayer include Initializers include Convert - def initialize(num_filters, filter_width, filter_height, + def initialize(num_filters, filter_size, weight_initializer: nil, bias_initializer: nil, - strides: [1, 1], + strides: 1, padding: false, weight_decay: 0) super() @num_filters = num_filters - @filter_width = filter_width - @filter_height = filter_height + @filter_size = filter_size.is_a?(Integer) ? [filter_size, filter_size] : filter_size @weight_initializer = (weight_initializer || RandomNormal.new) @bias_initializer = (bias_initializer || Zeros.new) - @strides = strides + @strides = strides.is_a?(Integer) ? [strides, strides] : strides @padding = padding @weight_decay = weight_decay end def self.load_hash(hash) - Conv2D.new(hash[:num_filters], hash[:filter_width], hash[:filter_height], + Conv2D.new(hash[:num_filters], hash[:filter_size], weight_initializer: Util.load_hash(hash[:weight_initializer]), bias_initializer: Util.load_hash(hash[:bias_initializer]), strides: hash[:strides], padding: hash[:padding], weight_decay: hash[:weight_decay]) end def build(model) super - prev_width, prev_height = prev_layer.shape[0..1] - @out_width, @out_height = out_size(prev_width, prev_height, @filter_width, @filter_height, @strides) + prev_w, prev_h = prev_layer.shape[0..1] + @out_size = out_size(prev_w, prev_h, *@filter_size, @strides) + out_w, out_h = @out_size if @padding - @pad = [prev_width - @out_width, prev_height - @out_height] - @out_width = prev_width - @out_height = prev_height + @pad = [prev_w - out_w, prev_h - out_h] + @out_size = [prev_w, prev_h] end end def forward(x) x = padding(x, @pad) if @padding @x_shape = x.shape - @col = im2col(x, @out_width, @out_height, @filter_width, @filter_height, @strides) + @col = im2col(x, *@out_size, *@filter_size, @strides) out = @col.dot(@params[:weight]) - out.reshape(x.shape[0], @out_width, @out_height, out.shape[3]) + out.reshape(x.shape[0], *@out_size, out.shape[3]) end def backward(dout) dout = dout.reshape(dout.shape[0..2].reduce(:*), dout.shape[3]) @grads[:weight] = @col.transpose.dot(dout) @@ -275,24 +274,23 @@ dridge = @weight_decay * @params[:weight] @grads[:weight] += dridge end @grads[:bias] = dout.sum(0) dcol = dout.dot(@params[:weight].transpose) - dx = col2im(dcol, @x_shape, @out_width, @out_height, @filter_width, @filter_height, @strides) + dx = col2im(dcol, @x_shape, *@out_size, *@filter_size, @strides) @padding ? back_padding(dx, @pad) : dx end def shape - [@out_width, @out_height, @num_filters] + [*@out_size, @num_filters] end def to_hash { name: self.class.name, num_filters: @num_filters, - filter_width: @filter_width, - filter_height: @filter_height, + filter_size: @filter_size, weight_initializer: @weight_initializer.to_hash, bias_initializer: @bias_initializer.to_hash, strides: @strides, padding: @padding, weight_decay: @weight_decay, @@ -301,65 +299,67 @@ private def init_params num_prev_filter = prev_layer.shape[2] - @params[:weight] = SFloat.new(num_prev_filter * @filter_width * @filter_height, @num_filters) + @params[:weight] = SFloat.new(num_prev_filter * @filter_size.reduce(:*), @num_filters) @params[:bias] = SFloat.new(@num_filters) @weight_initializer.init_param(self, :weight) @bias_initializer.init_param(self, :bias) end end class MaxPool2D < Layer include Convert - def initialize(pool_width, pool_height, strides: nil, padding: false) + def initialize(pool_size, strides: nil, padding: false) super() - @pool_width = pool_width - @pool_height = pool_height - @strides = strides ? strides : [@pool_width, @pool_height] + @pool_size = pool_size.is_a?(Integer) ? [pool_size, pool_size] : pool_size + @strides = if strides + strides.is_a?(Integer) ? [strides, strides] : strides + else + @pool_size.clone + end @padding = padding end def self.load_hash(hash) - MaxPool2D.new(hash[:pool_width], hash[:pool_height], strides: hash[:strides], padding: hash[:padding]) + MaxPool2D.new(hash[:pool_size], strides: hash[:strides], padding: hash[:padding]) end def build(model) super - prev_width, prev_height = prev_layer.shape[0..1] + prev_w, prev_h = prev_layer.shape[0..1] @num_channel = prev_layer.shape[2] - @out_width, @out_height = out_size(prev_width, prev_height, @pool_width, @pool_height, @strides) + @out_size = out_size(prev_w, prev_h, *@pool_size, @strides) + out_w, out_h = @out_size if @padding - @pad = [prev_width - @out_width, prev_height - @out_height] - @out_width = prev_width - @out_height = prev_height + @pad = [prev_w - out_w, prev_h - out_h] + @out_size = [prev_w, prev_h] end end def forward(x) x = padding(x, @pad) if @padding @x_shape = x.shape - col = im2col(x, @out_width, @out_height, @pool_width, @pool_height, @strides) - col = col.reshape(x.shape[0] * @out_width * @out_height * x.shape[3], @pool_width * @pool_height) + col = im2col(x, *@out_size, *@pool_size, @strides) + col = col.reshape(x.shape[0] * @out_size.reduce(:*) * x.shape[3], @pool_size.reduce(:*)) @max_index = col.max_index(1) - col.max(1).reshape(x.shape[0], @out_width, @out_height, x.shape[3]) + col.max(1).reshape(x.shape[0], *@out_size, x.shape[3]) end def backward(dout) - pool_size = @pool_width * @pool_height - dmax = SFloat.zeros(dout.size * pool_size) + dmax = SFloat.zeros(dout.size * @pool_size.reduce(:*)) dmax[@max_index] = dout.flatten - dcol = dmax.reshape(dout.shape[0..2].reduce(:*), dout.shape[3] * pool_size) - dx = col2im(dcol, @x_shape, @out_width, @out_height, @pool_width, @pool_height, @strides) + dcol = dmax.reshape(dout.shape[0..2].reduce(:*), dout.shape[3] * @pool_size.reduce(:*)) + dx = col2im(dcol, @x_shape, *@out_size, *@pool_size, @strides) @padding ? back_padding(dx, @pad) : dx end def shape - [@out_width, @out_height, @num_channel] + [*@out_size, @num_channel] end def to_hash { name: self.class.name, @@ -373,50 +373,51 @@ class UnPool2D < Layer include Convert - def initialize(unpool_width, unpool_height) + def initialize(unpool_size) super() - @unpool_width = unpool_width - @unpool_height = unpool_height + @unpool_size = unpool_size.is_a?(Integer) ? [unpool_size, unpool_size] : unpool_size end def self.load_hash(hash) - UnPool2D.new(hash[:unpool_width], hash[:unpool_height]) + UnPool2D.new(hash[:unpool_size]) end def build(model) super - @origin_width = prev_layer.shape[0] - @origin_height = prev_layer.shape[1] - @out_width = @origin_width * @unpool_width - @out_height = @origin_height * @unpool_height + prev_w, prev_h = prev_layer.shape[0..1] + unpool_w, unpool_h = @unpool_size + out_w = prev_w * unpool_w + out_h = prev_h * unpool_h + @out_size = [out_w, out_h] @num_channel = prev_layer.shape[2] end def forward(x) - unpool_size = @unpool_width * @unpool_height - x2 = SFloat.zeros(x.shape[0], x.shape[1], @unpool_width, x.shape[2], @unpool_height, x.shape[3]) + @x_shape = x.shape + unpool_w, unpool_h = @unpool_size + x2 = SFloat.zeros(x.shape[0], x.shape[1], unpool_w, x.shape[2], unpool_h, @num_channel) x2[true, true, 0, true, 0, true] = x - x2.reshape(x.shape[0], @out_width, @out_height, x.shape[3]) + x2.reshape(x.shape[0], *@out_size, x.shape[3]) end def backward(dout) - dout = dout.reshape(dout.shape[0], @origin_width, @unpool_width, @origin_height, @unpool_height, dout.shape[3]) + unpool_w, unpool_h = @unpool_size + dout = dout.reshape(dout.shape[0], @x_shape[0], unpool_w, @x_shape[1], unpool_h, @num_channel) dout[true, true, 0, true, 0, true].clone end def shape [@out_width, @out_height, @num_channel] end def to_hash { name: self.class.name, - unpool_width: @unpool_width, - unpool_height: @unpool_height, + unpool_size: @unpool_size, } end end @@ -498,10 +499,10 @@ end x end def backward(dout) - dout[@mask] = 0 if @model.training + dout[@mask] = 0 if @model.training? dout end def to_hash {name: self.class.name, dropout_ratio: @dropout_ratio}