ruby-dnn 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/examples/pix2pix/dcgan.rb +3 -7
- data/examples/pix2pix/train.rb +19 -12
- data/lib/dnn/core/losses.rb +2 -1
- data/lib/dnn/core/models.rb +47 -27
- data/lib/dnn/keras-model-convertor.rb +91 -32
- data/lib/dnn/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41b7dde05615d65bbc09fec893f67c0874a44aaff4dff8243c9ccdf97f5c9d7a
|
4
|
+
data.tar.gz: fea5cb29b787d4cbbba18f34ab2f3f4e6275f8018ebda6c335c9f3564194b109
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c18e653840184c9590966b18f36a98a843cf2d1d6ced1159c071ca21839476e4d6f0b6b36bb5319414a50c430cef8a1dd66bedc0ab87d16602896dff6006bc2e
|
7
|
+
data.tar.gz: ec7844e9a5bae664e8a5dd88d5684731c2a2bd3149c8131b8cbe606a9e10c30a68f7f8c4904644f931d2616cdc19dc345254934b792df4eb94117ab31c9b06f2
|
data/README.md
CHANGED
@@ -95,6 +95,8 @@ If you want to know more detailed information, please refer to the source code.
|
|
95
95
|
| Losses | MeanSquaredError, MeanAbsoluteError, Hinge, HuberLoss, SoftmaxCrossEntropy, SigmoidCrossEntropy |
|
96
96
|
|
97
97
|
## Datasets
|
98
|
+
By setting the environment variable "RUBY_DNN_DOWNLOADS_PATH", you can specify the path to read dataset.
|
99
|
+
|
98
100
|
● Iris
|
99
101
|
● MNIST
|
100
102
|
● Fashion-MNIST
|
data/examples/pix2pix/dcgan.rb
CHANGED
@@ -2,8 +2,6 @@ include DNN::Models
|
|
2
2
|
include DNN::Layers
|
3
3
|
|
4
4
|
class Generator < Model
|
5
|
-
attr_reader :generate_images
|
6
|
-
|
7
5
|
def initialize(input_shape)
|
8
6
|
super()
|
9
7
|
@input_shape = input_shape
|
@@ -27,7 +25,6 @@ class Generator < Model
|
|
27
25
|
@bn7 = BatchNormalization.new
|
28
26
|
@bn8 = BatchNormalization.new
|
29
27
|
@bn9 = BatchNormalization.new
|
30
|
-
@generate_images = nil
|
31
28
|
end
|
32
29
|
|
33
30
|
def forward(x)
|
@@ -75,7 +72,6 @@ class Generator < Model
|
|
75
72
|
|
76
73
|
x = @l11.(x)
|
77
74
|
x = Tanh.(x)
|
78
|
-
@generate_images = x.data
|
79
75
|
x
|
80
76
|
end
|
81
77
|
end
|
@@ -162,9 +158,9 @@ class DCGAN < Model
|
|
162
158
|
end
|
163
159
|
|
164
160
|
def forward(input)
|
165
|
-
|
161
|
+
images = @gen.(input)
|
166
162
|
@dis.disable_training
|
167
|
-
|
168
|
-
|
163
|
+
out = @dis.([input, images])
|
164
|
+
[images, out]
|
169
165
|
end
|
170
166
|
end
|
data/examples/pix2pix/train.rb
CHANGED
@@ -17,28 +17,35 @@ def load_dataset
|
|
17
17
|
[x_in, x_out]
|
18
18
|
end
|
19
19
|
|
20
|
+
initial_epoch = 1
|
21
|
+
|
20
22
|
epochs = 20
|
21
23
|
batch_size = 128
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
gen.setup(Adam.new(alpha: 0.0002, beta1: 0.5), MeanAbsoluteError.new)
|
28
|
-
dis.setup(Adam.new(alpha: 0.00001, beta1: 0.1), SigmoidCrossEntropy.new)
|
29
|
-
dcgan.setup(Adam.new(alpha: 0.0002, beta1: 0.5),
|
25
|
+
if initial_epoch == 1
|
26
|
+
gen = Generator.new([32, 32, 1])
|
27
|
+
dis = Discriminator.new([32, 32, 1], [32, 32, 3])
|
28
|
+
dcgan = DCGAN.new(gen, dis)
|
29
|
+
gen.setup(Adam.new(alpha: 0.0002, beta1: 0.5), MeanAbsoluteError.new)
|
30
|
+
dis.setup(Adam.new(alpha: 0.00001, beta1: 0.1), SigmoidCrossEntropy.new)
|
31
|
+
dcgan.setup(Adam.new(alpha: 0.0002, beta1: 0.5),
|
32
|
+
[MeanAbsoluteError.new, SigmoidCrossEntropy.new], loss_weights: [10, 1])
|
33
|
+
else
|
34
|
+
dcgan = DCGAN.load("trained/dcgan_model_epoch#{initial_epoch - 1}.marshal")
|
35
|
+
gen = dcgan.gen
|
36
|
+
dis = dcgan.dis
|
37
|
+
end
|
30
38
|
|
31
39
|
x_in, x_out = load_dataset
|
32
40
|
|
33
41
|
iter1 = DNN::Iterator.new(x_in, x_out)
|
34
42
|
iter2 = DNN::Iterator.new(x_in, x_out)
|
35
43
|
num_batchs = x_in.shape[0] / batch_size
|
36
|
-
(
|
44
|
+
(initial_epoch..epochs).each do |epoch|
|
37
45
|
num_batchs.times do |index|
|
38
46
|
x_in, x_out = iter1.next_batch(batch_size)
|
39
|
-
gen_loss = gen.train_on_batch(x_in, x_out)
|
40
47
|
|
41
|
-
images = gen.
|
48
|
+
images = gen.predict(x_in)
|
42
49
|
y_real = Numo::SFloat.ones(batch_size, 1)
|
43
50
|
y_fake = Numo::SFloat.zeros(batch_size, 1)
|
44
51
|
dis.enable_training
|
@@ -46,9 +53,9 @@ num_batchs = x_in.shape[0] / batch_size
|
|
46
53
|
dis_loss += dis.train_on_batch([x_in, images], y_fake)
|
47
54
|
|
48
55
|
x_in, x_out = iter2.next_batch(batch_size)
|
49
|
-
dcgan_loss = dcgan.train_on_batch(x_in, y_real)
|
56
|
+
dcgan_loss = dcgan.train_on_batch(x_in, [x_out, y_real])
|
50
57
|
|
51
|
-
puts "epoch: #{epoch}, index: #{index},
|
58
|
+
puts "epoch: #{epoch}, index: #{index}, dis_loss: #{dis_loss}, dcgan_loss: #{dcgan_loss}"
|
52
59
|
end
|
53
60
|
iter1.reset
|
54
61
|
iter2.reset
|
data/lib/dnn/core/losses.rb
CHANGED
@@ -19,11 +19,12 @@ module DNN
|
|
19
19
|
forward(y, t)
|
20
20
|
end
|
21
21
|
|
22
|
-
def loss(y, t, layers
|
22
|
+
def loss(y, t, layers: nil, loss_weight: nil)
|
23
23
|
unless y.shape == t.shape
|
24
24
|
raise DNNShapeError, "The shape of y does not match the t shape. y shape is #{y.shape}, but t shape is #{t.shape}."
|
25
25
|
end
|
26
26
|
loss = call(y, t)
|
27
|
+
loss *= loss_weight if loss_weight
|
27
28
|
loss = regularizers_forward(loss, layers) if layers
|
28
29
|
loss
|
29
30
|
end
|
data/lib/dnn/core/models.rb
CHANGED
@@ -109,6 +109,7 @@ module DNN
|
|
109
109
|
# This class deals with the model of the network.
|
110
110
|
class Model < Chain
|
111
111
|
attr_accessor :optimizer
|
112
|
+
attr_accessor :loss_weights
|
112
113
|
attr_reader :last_log
|
113
114
|
|
114
115
|
# Load marshal model.
|
@@ -126,6 +127,7 @@ module DNN
|
|
126
127
|
@optimizer = nil
|
127
128
|
@loss_func = nil
|
128
129
|
@built = false
|
130
|
+
@loss_weights = nil
|
129
131
|
@callbacks = []
|
130
132
|
@last_log = {}
|
131
133
|
end
|
@@ -139,7 +141,8 @@ module DNN
|
|
139
141
|
# Set optimizer and loss_func to model.
|
140
142
|
# @param [DNN::Optimizers::Optimizer] optimizer Optimizer to use for learning.
|
141
143
|
# @param [DNN::Losses::Loss] loss_func Loss function to use for learning.
|
142
|
-
|
144
|
+
# @param [Array | NilClass] loss_weights Setting loss weights contribution.
|
145
|
+
def setup(optimizer, loss_func, loss_weights: nil)
|
143
146
|
unless optimizer.is_a?(Optimizers::Optimizer)
|
144
147
|
raise TypeError, "optimizer:#{optimizer.class} is not an instance of DNN::Optimizers::Optimizer class."
|
145
148
|
end
|
@@ -148,6 +151,7 @@ module DNN
|
|
148
151
|
end
|
149
152
|
@optimizer = optimizer
|
150
153
|
self.loss_func = loss_func
|
154
|
+
@loss_weights = loss_weights
|
151
155
|
end
|
152
156
|
|
153
157
|
def loss_func
|
@@ -178,18 +182,21 @@ module DNN
|
|
178
182
|
# @param [Array | NilClass] test If you to test the model for every 1 epoch,
|
179
183
|
# specify [x_test, y_test]. Don't test to the model, specify nil.
|
180
184
|
# @param [Boolean] verbose Set true to display the log. If false is set, the log is not displayed.
|
185
|
+
# @param [Boolean] accuracy Set true to compute the accuracy.
|
181
186
|
def train(x, y, epochs,
|
182
187
|
batch_size: 1,
|
183
188
|
initial_epoch: 1,
|
184
189
|
test: nil,
|
185
|
-
verbose: true
|
190
|
+
verbose: true,
|
191
|
+
accuracy: true)
|
186
192
|
check_xy_type(x, y)
|
187
193
|
train_iterator = Iterator.new(x, y)
|
188
194
|
train_by_iterator(train_iterator, epochs,
|
189
195
|
batch_size: batch_size,
|
190
196
|
initial_epoch: initial_epoch,
|
191
197
|
test: test,
|
192
|
-
verbose: verbose
|
198
|
+
verbose: verbose,
|
199
|
+
accuracy: accuracy)
|
193
200
|
end
|
194
201
|
|
195
202
|
alias fit train
|
@@ -203,11 +210,13 @@ module DNN
|
|
203
210
|
# @param [Array | NilClass] test If you to test the model for every 1 epoch,
|
204
211
|
# specify [x_test, y_test]. Don't test to the model, specify nil.
|
205
212
|
# @param [Boolean] verbose Set true to display the log. If false is set, the log is not displayed.
|
213
|
+
# @param [Boolean] accuracy Set true to compute the accuracy.
|
206
214
|
def train_by_iterator(train_iterator, epochs,
|
207
215
|
batch_size: 1,
|
208
216
|
initial_epoch: 1,
|
209
217
|
test: nil,
|
210
|
-
verbose: true
|
218
|
+
verbose: true,
|
219
|
+
accuracy: true)
|
211
220
|
raise DNNError, "The model is not optimizer setup complete." unless @optimizer
|
212
221
|
raise DNNError, "The model is not loss_func setup complete." unless @loss_func
|
213
222
|
|
@@ -242,11 +251,18 @@ module DNN
|
|
242
251
|
|
243
252
|
if test
|
244
253
|
acc, loss = if test.is_a?(Array)
|
245
|
-
evaluate(test[0], test[1], batch_size: batch_size)
|
254
|
+
evaluate(test[0], test[1], batch_size: batch_size, accuracy: accuracy)
|
246
255
|
else
|
247
|
-
evaluate_by_iterator(test, batch_size: batch_size)
|
256
|
+
evaluate_by_iterator(test, batch_size: batch_size, accuracy: accuracy)
|
248
257
|
end
|
249
|
-
|
258
|
+
if verbose
|
259
|
+
metrics = if accuracy
|
260
|
+
{ accuracy: acc, test_loss: loss }
|
261
|
+
else
|
262
|
+
{ test_loss: loss }
|
263
|
+
end
|
264
|
+
print " " + metrics_to_str(metrics)
|
265
|
+
end
|
250
266
|
end
|
251
267
|
puts "" if verbose
|
252
268
|
call_callbacks(:after_epoch)
|
@@ -285,17 +301,16 @@ module DNN
|
|
285
301
|
if output_tensors.is_a?(Array)
|
286
302
|
loss_data = []
|
287
303
|
output_tensors.each.with_index do |out, i|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
end
|
304
|
+
loss_opt = {}
|
305
|
+
loss_opt[:layers] = layers if i == 0
|
306
|
+
loss_opt[:loss_weight] = @loss_weights[i] if @loss_weights
|
307
|
+
loss = @loss_func[i].loss(out, Tensor.convert(y[i]), **loss_opt)
|
293
308
|
loss_data << loss.data.to_f
|
294
309
|
loss.link.backward(Xumo::SFloat.ones(y[i][0...1, false].shape[0], 1))
|
295
310
|
end
|
296
311
|
else
|
297
312
|
out = output_tensors
|
298
|
-
loss = @loss_func.loss(out, Tensor.convert(y), layers)
|
313
|
+
loss = @loss_func.loss(out, Tensor.convert(y), layers: layers)
|
299
314
|
loss_data = loss.data.to_f
|
300
315
|
loss.link.backward(Xumo::SFloat.ones(y[0...1, false].shape[0], 1))
|
301
316
|
end
|
@@ -310,16 +325,18 @@ module DNN
|
|
310
325
|
# @param [Numo::SFloat] y Output test data.
|
311
326
|
# @param [Integer] batch_size Batch size used for one test.
|
312
327
|
# @return [Array] Returns the test data accuracy and mean loss in the form [accuracy, mean_loss].
|
313
|
-
|
328
|
+
# If accuracy is not needed returns in the form [nil, mean_loss].
|
329
|
+
def evaluate(x, y, batch_size: 100, accuracy: true)
|
314
330
|
check_xy_type(x, y)
|
315
|
-
evaluate_by_iterator(Iterator.new(x, y, random: false), batch_size: batch_size)
|
331
|
+
evaluate_by_iterator(Iterator.new(x, y, random: false), batch_size: batch_size, accuracy: accuracy)
|
316
332
|
end
|
317
333
|
|
318
334
|
# Evaluate model by iterator.
|
319
335
|
# @param [DNN::Iterator] test_iterator Iterator used for testing.
|
320
336
|
# @param [Integer] batch_size Batch size used for one test.
|
321
337
|
# @return [Array] Returns the test data accuracy and mean loss in the form [accuracy, mean_loss].
|
322
|
-
|
338
|
+
# If accuracy is not needed returns in the form [nil, mean_loss].
|
339
|
+
def evaluate_by_iterator(test_iterator, batch_size: 100, accuracy: true)
|
323
340
|
num_test_datas = test_iterator.num_datas
|
324
341
|
batch_size = batch_size >= num_test_datas ? num_test_datas : batch_size
|
325
342
|
if @loss_func.is_a?(Array)
|
@@ -331,27 +348,28 @@ module DNN
|
|
331
348
|
end
|
332
349
|
max_steps = (num_test_datas.to_f / batch_size).ceil
|
333
350
|
test_iterator.foreach(batch_size) do |x_batch, y_batch|
|
334
|
-
correct, loss_value = test_on_batch(x_batch, y_batch)
|
351
|
+
correct, loss_value = test_on_batch(x_batch, y_batch, accuracy: accuracy)
|
335
352
|
if @loss_func.is_a?(Array)
|
336
353
|
@loss_func.each_index do |i|
|
337
|
-
total_correct[i] += correct[i]
|
354
|
+
total_correct[i] += correct[i] if accuracy
|
338
355
|
sum_loss[i] += loss_value[i]
|
339
356
|
end
|
340
357
|
else
|
341
|
-
total_correct += correct
|
358
|
+
total_correct += correct if accuracy
|
342
359
|
sum_loss += loss_value
|
343
360
|
end
|
344
361
|
end
|
362
|
+
acc = nil
|
345
363
|
if @loss_func.is_a?(Array)
|
346
364
|
mean_loss = Array.new(@loss_func.length, 0)
|
347
|
-
acc = Array.new(@loss_func.length, 0)
|
365
|
+
acc = Array.new(@loss_func.length, 0) if accuracy
|
348
366
|
@loss_func.each_index do |i|
|
349
367
|
mean_loss[i] += sum_loss[i] / max_steps
|
350
|
-
acc[i] += total_correct[i].to_f / num_test_datas
|
368
|
+
acc[i] += total_correct[i].to_f / num_test_datas if accuracy
|
351
369
|
end
|
352
370
|
else
|
353
371
|
mean_loss = sum_loss / max_steps
|
354
|
-
acc = total_correct.to_f / num_test_datas
|
372
|
+
acc = total_correct.to_f / num_test_datas if accuracy
|
355
373
|
end
|
356
374
|
@last_log[:test_loss] = mean_loss
|
357
375
|
@last_log[:test_accuracy] = acc
|
@@ -361,22 +379,24 @@ module DNN
|
|
361
379
|
# Evaluate once.
|
362
380
|
# @param [Numo::SFloat | Array] x Input test data.
|
363
381
|
# @param [Numo::SFloat | Array] y Output test data.
|
364
|
-
# @return [Array] Returns the test data accuracy and mean loss in the form [accuracy,
|
365
|
-
|
382
|
+
# @return [Array] Returns the test data accuracy and mean loss in the form [accuracy, loss].
|
383
|
+
# If accuracy is not needed returns in the form [nil, loss].
|
384
|
+
def test_on_batch(x, y, accuracy: true)
|
366
385
|
call_callbacks(:before_test_on_batch)
|
367
386
|
DNN.learning_phase = false
|
368
387
|
output_tensors = call(Tensor.convert(x))
|
388
|
+
correct = nil
|
369
389
|
if output_tensors.is_a?(Array)
|
370
|
-
correct = []
|
390
|
+
correct = [] if accuracy
|
371
391
|
loss_data = []
|
372
392
|
output_tensors.each.with_index do |out, i|
|
373
|
-
correct << accuracy(out.data, y[i])
|
393
|
+
correct << accuracy(out.data, y[i]) if accuracy
|
374
394
|
loss = @loss_func[i].(out, Tensor.convert(y[i]))
|
375
395
|
loss_data << loss.data.to_f
|
376
396
|
end
|
377
397
|
else
|
378
398
|
out = output_tensors
|
379
|
-
correct = accuracy(out.data, y)
|
399
|
+
correct = accuracy(out.data, y) if accuracy
|
380
400
|
loss = @loss_func.(out, Tensor.convert(y))
|
381
401
|
loss_data = loss.data.to_f
|
382
402
|
end
|
@@ -27,36 +27,51 @@ end
|
|
27
27
|
|
28
28
|
class DNNKerasModelConvertError < DNN::DNNError; end
|
29
29
|
|
30
|
+
class DNNKerasLayerNotConvertSupportError < DNNKerasModelConvertError; end
|
31
|
+
|
30
32
|
class KerasModelConvertor
|
31
33
|
pyfrom :"keras.models", import: :load_model
|
32
34
|
|
33
|
-
def self.
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
def self.load(k_model_name, k_weights_name = nil)
|
36
|
+
k_model = load_model(k_model_name)
|
37
|
+
k_model.load_weights(k_weights_name) if k_weights_name
|
38
|
+
self.new(k_model)
|
37
39
|
end
|
38
40
|
|
39
|
-
def initialize(
|
40
|
-
@k_model =
|
41
|
+
def initialize(k_model)
|
42
|
+
@k_model = k_model
|
41
43
|
end
|
42
44
|
|
43
|
-
def convert
|
45
|
+
def convert(not_support_to_nil: false, debug_message: false)
|
44
46
|
unless @k_model.__class__.__name__ == "Sequential"
|
45
47
|
raise DNNKerasModelConvertError.new("#{@k_model.__class__.__name__} models do not support convert.")
|
46
48
|
end
|
47
|
-
layers = convert_layers(
|
48
|
-
input_shape = @k_model.layers[0].input_shape.to_a[1..-1]
|
49
|
-
input_layer = DNN::Layers::InputLayer.new(input_shape)
|
50
|
-
input_layer.build(input_shape)
|
51
|
-
layers.unshift(input_layer)
|
49
|
+
layers = convert_layers(not_support_to_nil: not_support_to_nil, debug_message: debug_message)
|
52
50
|
dnn_model = DNN::Models::Sequential.new(layers)
|
53
51
|
dnn_model
|
54
52
|
end
|
55
53
|
|
56
|
-
def convert_layers(
|
57
|
-
|
58
|
-
|
54
|
+
def convert_layers(not_support_to_nil: false, debug_message: false)
|
55
|
+
layers = []
|
56
|
+
@k_model.layers.each do |k_layer|
|
57
|
+
layer = if not_support_to_nil
|
58
|
+
begin
|
59
|
+
layer_convert(k_layer)
|
60
|
+
rescue DNNKerasLayerNotConvertSupportError => e
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
else
|
64
|
+
layer_convert(k_layer)
|
65
|
+
end
|
66
|
+
if layer.is_a?(Array)
|
67
|
+
layer.each { |l| puts "Converted #{l.class.name} layer" } if debug_message
|
68
|
+
layers += layer
|
69
|
+
else
|
70
|
+
puts "Converted #{layer.class.name} layer" if debug_message
|
71
|
+
layers << layer
|
72
|
+
end
|
59
73
|
end
|
74
|
+
layers
|
60
75
|
end
|
61
76
|
|
62
77
|
private
|
@@ -67,7 +82,7 @@ class KerasModelConvertor
|
|
67
82
|
if respond_to?(method_name, true)
|
68
83
|
send(method_name, k_layer)
|
69
84
|
else
|
70
|
-
raise
|
85
|
+
raise DNNKerasLayerNotConvertSupportError.new("#{k_layer_name} layer do not support convert.")
|
71
86
|
end
|
72
87
|
end
|
73
88
|
|
@@ -82,18 +97,34 @@ class KerasModelConvertor
|
|
82
97
|
dnn_layer.build(input_shape)
|
83
98
|
end
|
84
99
|
|
100
|
+
def convert_InputLayer(k_input_layer)
|
101
|
+
input_shape, output_shape = get_k_layer_shape(k_input_layer)
|
102
|
+
input_layer = DNN::Layers::InputLayer.new(input_shape)
|
103
|
+
input_layer.build(input_shape)
|
104
|
+
input_layer
|
105
|
+
end
|
106
|
+
|
85
107
|
def convert_Dense(k_dense)
|
86
108
|
input_shape, output_shape = get_k_layer_shape(k_dense)
|
87
109
|
dense = DNN::Layers::Dense.new(output_shape[0])
|
88
110
|
dense.build(input_shape)
|
89
111
|
dense.weight.data = Numpy.to_na(k_dense.get_weights[0])
|
90
112
|
dense.bias.data = Numpy.to_na(k_dense.get_weights[1])
|
91
|
-
dense
|
113
|
+
returns = [dense]
|
114
|
+
unless k_dense.get_config[:activation] == "linear"
|
115
|
+
returns << activation_to_dnn_layer(k_dense.get_config[:activation], output_shape)
|
116
|
+
end
|
117
|
+
returns
|
92
118
|
end
|
93
119
|
|
94
120
|
def convert_Activation(k_activation)
|
121
|
+
input_shape, output_shape = get_k_layer_shape(k_activation)
|
95
122
|
activation_name = k_activation.get_config[:activation].to_s
|
96
|
-
|
123
|
+
activation_to_dnn_layer(activation_name, input_shape)
|
124
|
+
end
|
125
|
+
|
126
|
+
def activation_to_dnn_layer(activation_name, shape)
|
127
|
+
activation = case activation_name
|
97
128
|
when "sigmoid"
|
98
129
|
DNN::Layers::Sigmoid.new
|
99
130
|
when "tanh"
|
@@ -105,7 +136,7 @@ class KerasModelConvertor
|
|
105
136
|
else
|
106
137
|
raise DNNKerasModelConvertError.new("#{activation_name} activation do not support convert.")
|
107
138
|
end
|
108
|
-
|
139
|
+
activation.build(shape)
|
109
140
|
activation
|
110
141
|
end
|
111
142
|
|
@@ -136,19 +167,29 @@ class KerasModelConvertor
|
|
136
167
|
build_dnn_layer(k_conv2d, conv2d)
|
137
168
|
conv2d.filters = Numpy.to_na(k_conv2d.get_weights[0])
|
138
169
|
conv2d.bias.data = Numpy.to_na(k_conv2d.get_weights[1])
|
139
|
-
conv2d
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
170
|
+
returns = [conv2d]
|
171
|
+
unless k_conv2d.get_config[:activation] == "linear"
|
172
|
+
input_shape, output_shape = get_k_layer_shape(k_conv2d)
|
173
|
+
returns << activation_to_dnn_layer(k_conv2d.get_config[:activation], output_shape)
|
174
|
+
end
|
175
|
+
returns
|
176
|
+
end
|
177
|
+
|
178
|
+
def convert_Conv2DTranspose(k_conv2d_t)
|
179
|
+
padding = k_conv2d_t.get_config[:padding].to_s == "same" ? true : false
|
180
|
+
filter_size = k_conv2d_t.get_config[:kernel_size].to_a
|
181
|
+
strides = k_conv2d_t.get_config[:strides].to_a
|
182
|
+
num_filters = k_conv2d_t.get_config[:filters]
|
183
|
+
conv2d_t = DNN::Layers::Conv2DTranspose.new(num_filters, filter_size, padding: padding, strides: strides)
|
184
|
+
build_dnn_layer(k_conv2d_t, conv2d_t)
|
185
|
+
conv2d_t.filters = Numpy.to_na(k_conv2d_t.get_weights[0])
|
186
|
+
conv2d_t.bias.data = Numpy.to_na(k_conv2d_t.get_weights[1])
|
187
|
+
returns = [conv2d_t]
|
188
|
+
unless conv2d_t.get_config[:activation] == "linear"
|
189
|
+
input_shape, output_shape = get_k_layer_shape(k_conv2d)
|
190
|
+
returns << activation_to_dnn_layer(conv2d_t.get_config[:activation], output_shape)
|
191
|
+
end
|
192
|
+
returns
|
152
193
|
end
|
153
194
|
|
154
195
|
def convert_MaxPooling2D(k_max_pool2d)
|
@@ -160,6 +201,24 @@ class KerasModelConvertor
|
|
160
201
|
max_pool2d
|
161
202
|
end
|
162
203
|
|
204
|
+
def convert_AveragePooling2D(k_avg_pool2d)
|
205
|
+
padding = k_avg_pool2d.get_config[:padding].to_s == "same" ? true : false
|
206
|
+
pool_size = k_avg_pool2d.get_config[:pool_size].to_a
|
207
|
+
strides = k_avg_pool2d.get_config[:strides].to_a
|
208
|
+
avg_pool2d = DNN::Layers::AvgPool2D.new(pool_size, padding: padding, strides: strides)
|
209
|
+
build_dnn_layer(k_avg_pool2d, avg_pool2d)
|
210
|
+
avg_pool2d
|
211
|
+
end
|
212
|
+
|
213
|
+
def convert_GlobalAveragePooling2D(k_glb_avg_pool2d)
|
214
|
+
padding = k_glb_avg_pool2d.get_config[:padding].to_s == "same" ? true : false
|
215
|
+
pool_size = k_glb_avg_pool2d.get_config[:pool_size].to_a
|
216
|
+
strides = k_glb_avg_pool2d.get_config[:strides].to_a
|
217
|
+
glb_avg_pool2d = DNN::Layers::GlobalAvgPool2D.new
|
218
|
+
build_dnn_layer(k_glb_avg_pool2d, glb_avg_pool2d)
|
219
|
+
glb_avg_pool2d
|
220
|
+
end
|
221
|
+
|
163
222
|
def convert_UpSampling2D(k_upsampling2d)
|
164
223
|
input_shape, output_shape = get_k_layer_shape(k_upsampling2d)
|
165
224
|
unpool_size = k_upsampling2d.get_config[:size].to_a
|
data/lib/dnn/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-dnn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- unagiootoro
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02-
|
11
|
+
date: 2020-02-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: numo-narray
|