lib/dnn/keras-model-convertor.rb in ruby-dnn-1.1.1 vs lib/dnn/keras-model-convertor.rb in ruby-dnn-1.1.2
- old
+ new
@@ -25,51 +25,66 @@
end
end
class DNNKerasModelConvertError < DNN::DNNError; end
+class DNNKerasLayerNotConvertSupportError < DNNKerasModelConvertError; end
+
class KerasModelConvertor
pyfrom :"keras.models", import: :load_model
- def self.k_load_model(k_model_name, k_weights_name)
- model = load_model(k_model_name)
- model.load_weights(k_weights_name) if k_weights_name
- model
+ def self.load(k_model_name, k_weights_name = nil)
+ k_model = load_model(k_model_name)
+ k_model.load_weights(k_weights_name) if k_weights_name
+ self.new(k_model)
end
- def initialize(k_model_name, k_weights_name = nil)
- @k_model = KerasModelConvertor.k_load_model(k_model_name, k_weights_name)
+ def initialize(k_model)
+ @k_model = k_model
end
- def convert
+ def convert(not_support_to_nil: false, debug_message: false)
unless @k_model.__class__.__name__ == "Sequential"
raise DNNKerasModelConvertError.new("#{@k_model.__class__.__name__} models do not support convert.")
end
- layers = convert_layers(@k_model.layers)
- input_shape = @k_model.layers[0].input_shape.to_a[1..-1]
- input_layer = DNN::Layers::InputLayer.new(input_shape)
- input_layer.build(input_shape)
- layers.unshift(input_layer)
+ layers = convert_layers(not_support_to_nil: not_support_to_nil, debug_message: debug_message)
dnn_model = DNN::Models::Sequential.new(layers)
dnn_model
end
- def convert_layers(k_layers)
- k_layers.map do |k_layer|
- layer_convert(k_layer)
+ def convert_layers(not_support_to_nil: false, debug_message: false)
+ layers = []
+ @k_model.layers.each do |k_layer|
+ layer = if not_support_to_nil
+ begin
+ layer_convert(k_layer)
+ rescue DNNKerasLayerNotConvertSupportError => e
+ nil
+ end
+ else
+ layer_convert(k_layer)
+ end
+ if layer.is_a?(Array)
+ layer.each { |l| puts "Converted #{l.class.name} layer" } if debug_message
+ layers += layer
+ else
+ puts "Converted #{layer.class.name} layer" if debug_message
+ layers << layer
+ end
end
+ layers
end
private
def layer_convert(k_layer)
k_layer_name = k_layer.__class__.__name__
method_name = "convert_" + k_layer_name
if respond_to?(method_name, true)
send(method_name, k_layer)
else
- raise DNNKerasModelConvertError.new("#{k_layer_name} layer do not support convert.")
+ raise DNNKerasLayerNotConvertSupportError.new("#{k_layer_name} layer do not support convert.")
end
end
def get_k_layer_shape(k_layer)
input_shape = k_layer.input_shape.to_a[1..-1]
@@ -80,22 +95,38 @@
def build_dnn_layer(k_layer, dnn_layer)
input_shape, output_shape = get_k_layer_shape(k_layer)
dnn_layer.build(input_shape)
end
+ def convert_InputLayer(k_input_layer)
+ input_shape, output_shape = get_k_layer_shape(k_input_layer)
+ input_layer = DNN::Layers::InputLayer.new(input_shape)
+ input_layer.build(input_shape)
+ input_layer
+ end
+
def convert_Dense(k_dense)
input_shape, output_shape = get_k_layer_shape(k_dense)
dense = DNN::Layers::Dense.new(output_shape[0])
dense.build(input_shape)
dense.weight.data = Numpy.to_na(k_dense.get_weights[0])
dense.bias.data = Numpy.to_na(k_dense.get_weights[1])
- dense
+ returns = [dense]
+ unless k_dense.get_config[:activation] == "linear"
+ returns << activation_to_dnn_layer(k_dense.get_config[:activation], output_shape)
+ end
+ returns
end
def convert_Activation(k_activation)
+ input_shape, output_shape = get_k_layer_shape(k_activation)
activation_name = k_activation.get_config[:activation].to_s
- activation = case k_activation.get_config[:activation].to_s
+ activation_to_dnn_layer(activation_name, input_shape)
+ end
+
+ def activation_to_dnn_layer(activation_name, shape)
+ activation = case activation_name
when "sigmoid"
DNN::Layers::Sigmoid.new
when "tanh"
DNN::Layers::Tanh.new
when "relu"
@@ -103,11 +134,11 @@
when "softmax"
DNN::Layers::Softmax.new
else
raise DNNKerasModelConvertError.new("#{activation_name} activation do not support convert.")
end
- build_dnn_layer(k_activation, activation)
+ activation.build(shape)
activation
end
def convert_Dropout(k_dropout)
dropout_ratio = k_dropout.get_config[:rate]
@@ -134,31 +165,59 @@
num_filters = k_conv2d.get_config[:filters]
conv2d = DNN::Layers::Conv2D.new(num_filters, filter_size, padding: padding, strides: strides)
build_dnn_layer(k_conv2d, conv2d)
conv2d.filters = Numpy.to_na(k_conv2d.get_weights[0])
conv2d.bias.data = Numpy.to_na(k_conv2d.get_weights[1])
- conv2d
+ returns = [conv2d]
+ unless k_conv2d.get_config[:activation] == "linear"
+ input_shape, output_shape = get_k_layer_shape(k_conv2d)
+ returns << activation_to_dnn_layer(k_conv2d.get_config[:activation], output_shape)
+ end
+ returns
end
- def convert_Conv2DTranspose(k_conv2d)
- padding = k_conv2d.get_config[:padding].to_s == "same" ? true : false
- filter_size = k_conv2d.get_config[:kernel_size].to_a
- strides = k_conv2d.get_config[:strides].to_a
- num_filters = k_conv2d.get_config[:filters]
- conv2d = DNN::Layers::Conv2DTranspose.new(num_filters, filter_size, padding: padding, strides: strides)
- build_dnn_layer(k_conv2d, conv2d)
- conv2d.filters = Numpy.to_na(k_conv2d.get_weights[0])
- conv2d.bias.data = Numpy.to_na(k_conv2d.get_weights[1])
- conv2d
+ def convert_Conv2DTranspose(k_conv2d_t)
+ padding = k_conv2d_t.get_config[:padding].to_s == "same" ? true : false
+ filter_size = k_conv2d_t.get_config[:kernel_size].to_a
+ strides = k_conv2d_t.get_config[:strides].to_a
+ num_filters = k_conv2d_t.get_config[:filters]
+ conv2d_t = DNN::Layers::Conv2DTranspose.new(num_filters, filter_size, padding: padding, strides: strides)
+ build_dnn_layer(k_conv2d_t, conv2d_t)
+ conv2d_t.filters = Numpy.to_na(k_conv2d_t.get_weights[0])
+ conv2d_t.bias.data = Numpy.to_na(k_conv2d_t.get_weights[1])
+ returns = [conv2d_t]
+ unless conv2d_t.get_config[:activation] == "linear"
+ input_shape, output_shape = get_k_layer_shape(k_conv2d)
+ returns << activation_to_dnn_layer(conv2d_t.get_config[:activation], output_shape)
+ end
+ returns
end
def convert_MaxPooling2D(k_max_pool2d)
padding = k_max_pool2d.get_config[:padding].to_s == "same" ? true : false
pool_size = k_max_pool2d.get_config[:pool_size].to_a
strides = k_max_pool2d.get_config[:strides].to_a
max_pool2d = DNN::Layers::MaxPool2D.new(pool_size, padding: padding, strides: strides)
build_dnn_layer(k_max_pool2d, max_pool2d)
max_pool2d
+ end
+
+ def convert_AveragePooling2D(k_avg_pool2d)
+ padding = k_avg_pool2d.get_config[:padding].to_s == "same" ? true : false
+ pool_size = k_avg_pool2d.get_config[:pool_size].to_a
+ strides = k_avg_pool2d.get_config[:strides].to_a
+ avg_pool2d = DNN::Layers::AvgPool2D.new(pool_size, padding: padding, strides: strides)
+ build_dnn_layer(k_avg_pool2d, avg_pool2d)
+ avg_pool2d
+ end
+
+ def convert_GlobalAveragePooling2D(k_glb_avg_pool2d)
+ padding = k_glb_avg_pool2d.get_config[:padding].to_s == "same" ? true : false
+ pool_size = k_glb_avg_pool2d.get_config[:pool_size].to_a
+ strides = k_glb_avg_pool2d.get_config[:strides].to_a
+ glb_avg_pool2d = DNN::Layers::GlobalAvgPool2D.new
+ build_dnn_layer(k_glb_avg_pool2d, glb_avg_pool2d)
+ glb_avg_pool2d
end
def convert_UpSampling2D(k_upsampling2d)
input_shape, output_shape = get_k_layer_shape(k_upsampling2d)
unpool_size = k_upsampling2d.get_config[:size].to_a