ruby-dnn 0.14.0 → 0.14.1
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/examples/api-examples/early_stopping_example.rb +58 -0
- data/examples/api-examples/initializer_example.rb +54 -0
- data/examples/api-examples/regularizer_example.rb +55 -0
- data/examples/api-examples/save_example.rb +85 -0
- data/lib/dnn/core/callbacks.rb +2 -2
- data/lib/dnn/core/layers.rb +13 -5
- data/lib/dnn/core/losses.rb +1 -1
- data/lib/dnn/core/models.rb +11 -5
- data/lib/dnn/image.rb +18 -10
- data/lib/dnn/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a07d117f60cfce7327a63514df0ffb2bf2228d4dfaa531d5b1c849ad581c5aa3
|
4
|
+
data.tar.gz: 460158875978df670f99a501dc1a5878c392517d2c5123f13c3c8c96718f3a5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8cbb2fc0992b458f5af4176d2757f9e1222aba1cf1a980db5f8c4e64c20f8442bb1c6c103f78adbe5855bfdd7a8f01b33ffe3978b369b20b52efbdd9de7af4c
|
7
|
+
data.tar.gz: a67ced6f09ea4d1fd5c81a7e13a1ac1b35d46512b54e06fa3773025036fed3cf5200b5cefb985defe4debd8fc2b8a669fa9a48a2ea21ee6721ff539c89c1d944
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "dnn"
|
2
|
+
require "dnn/datasets/mnist"
|
3
|
+
# If you use numo/linalg then please uncomment out.
|
4
|
+
# require "numo/linalg/autoloader"
|
5
|
+
|
6
|
+
include DNN::Models
|
7
|
+
include DNN::Layers
|
8
|
+
include DNN::Optimizers
|
9
|
+
include DNN::Losses
|
10
|
+
include DNN::Callbacks
|
11
|
+
MNIST = DNN::MNIST
|
12
|
+
|
13
|
+
EPOCHS = 3
|
14
|
+
BATCH_SIZE = 128
|
15
|
+
|
16
|
+
x_train, y_train = MNIST.load_train
|
17
|
+
x_test, y_test = MNIST.load_test
|
18
|
+
|
19
|
+
x_train = Numo::SFloat.cast(x_train).reshape(x_train.shape[0], 784)
|
20
|
+
x_test = Numo::SFloat.cast(x_test).reshape(x_test.shape[0], 784)
|
21
|
+
|
22
|
+
x_train /= 255
|
23
|
+
x_test /= 255
|
24
|
+
|
25
|
+
y_train = DNN::Utils.to_categorical(y_train, 10, Numo::SFloat)
|
26
|
+
y_test = DNN::Utils.to_categorical(y_test, 10, Numo::SFloat)
|
27
|
+
|
28
|
+
class MLP < Model
|
29
|
+
def initialize
|
30
|
+
super
|
31
|
+
@l1 = Dense.new(256)
|
32
|
+
@l2 = Dense.new(256)
|
33
|
+
@l3 = Dense.new(10)
|
34
|
+
@bn1 = BatchNormalization.new
|
35
|
+
@bn2 = BatchNormalization.new
|
36
|
+
end
|
37
|
+
|
38
|
+
def call(x)
|
39
|
+
x = InputLayer.(x)
|
40
|
+
x = @l1.(x)
|
41
|
+
x = @bn1.(x)
|
42
|
+
x = ReLU.(x)
|
43
|
+
x = @l2.(x)
|
44
|
+
x = @bn2.(x)
|
45
|
+
x = ReLU.(x)
|
46
|
+
x = @l3.(x)
|
47
|
+
x
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
model = MLP.new
|
52
|
+
model.setup(Adam.new, SoftmaxCrossEntropy.new)
|
53
|
+
|
54
|
+
# Add EarlyStopping callback for model.
|
55
|
+
# This callback is stop the training when test accuracy is over 0.9.
|
56
|
+
model.add_callback(EarlyStopping.new(:test_accuracy, 0.9))
|
57
|
+
|
58
|
+
model.train(x_train, y_train, EPOCHS, batch_size: BATCH_SIZE, test: [x_test, y_test])
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "dnn"
|
2
|
+
require "dnn/datasets/mnist"
|
3
|
+
# If you use numo/linalg then please uncomment out.
|
4
|
+
# require "numo/linalg/autoloader"
|
5
|
+
|
6
|
+
include DNN::Models
|
7
|
+
include DNN::Layers
|
8
|
+
include DNN::Initializers
|
9
|
+
include DNN::Optimizers
|
10
|
+
include DNN::Losses
|
11
|
+
MNIST = DNN::MNIST
|
12
|
+
|
13
|
+
EPOCHS = 3
|
14
|
+
BATCH_SIZE = 128
|
15
|
+
|
16
|
+
x_train, y_train = MNIST.load_train
|
17
|
+
x_test, y_test = MNIST.load_test
|
18
|
+
|
19
|
+
x_train = Numo::SFloat.cast(x_train).reshape(x_train.shape[0], 784)
|
20
|
+
x_test = Numo::SFloat.cast(x_test).reshape(x_test.shape[0], 784)
|
21
|
+
|
22
|
+
x_train /= 255
|
23
|
+
x_test /= 255
|
24
|
+
|
25
|
+
y_train = DNN::Utils.to_categorical(y_train, 10, Numo::SFloat)
|
26
|
+
y_test = DNN::Utils.to_categorical(y_test, 10, Numo::SFloat)
|
27
|
+
|
28
|
+
class MLP < Model
|
29
|
+
def initialize
|
30
|
+
super
|
31
|
+
# Set the initial values of weight and bias to the initial values of He.
|
32
|
+
@l1 = Dense.new(256, weight_initializer: He.new, bias_initializer: He.new)
|
33
|
+
@l2 = Dense.new(256, weight_initializer: He.new, bias_initializer: He.new)
|
34
|
+
@l3 = Dense.new(10, weight_initializer: He.new, bias_initializer: He.new)
|
35
|
+
@bn1 = BatchNormalization.new
|
36
|
+
@bn2 = BatchNormalization.new
|
37
|
+
end
|
38
|
+
|
39
|
+
def call(x)
|
40
|
+
x = InputLayer.(x)
|
41
|
+
x = @l1.(x)
|
42
|
+
x = @bn1.(x)
|
43
|
+
x = ReLU.(x)
|
44
|
+
x = @l2.(x)
|
45
|
+
x = @bn2.(x)
|
46
|
+
x = ReLU.(x)
|
47
|
+
x = @l3.(x)
|
48
|
+
x
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
model = MLP.new
|
53
|
+
model.setup(Adam.new, SoftmaxCrossEntropy.new)
|
54
|
+
model.train(x_train, y_train, EPOCHS, batch_size: BATCH_SIZE, test: [x_test, y_test])
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "dnn"
|
2
|
+
require "dnn/datasets/mnist"
|
3
|
+
# If you use numo/linalg then please uncomment out.
|
4
|
+
# require "numo/linalg/autoloader"
|
5
|
+
|
6
|
+
include DNN::Models
|
7
|
+
include DNN::Layers
|
8
|
+
include DNN::Regularizers
|
9
|
+
include DNN::Optimizers
|
10
|
+
include DNN::Losses
|
11
|
+
MNIST = DNN::MNIST
|
12
|
+
|
13
|
+
EPOCHS = 3
|
14
|
+
BATCH_SIZE = 128
|
15
|
+
L2_LAMBDA = 0.01
|
16
|
+
|
17
|
+
x_train, y_train = MNIST.load_train
|
18
|
+
x_test, y_test = MNIST.load_test
|
19
|
+
|
20
|
+
x_train = Numo::SFloat.cast(x_train).reshape(x_train.shape[0], 784)
|
21
|
+
x_test = Numo::SFloat.cast(x_test).reshape(x_test.shape[0], 784)
|
22
|
+
|
23
|
+
x_train /= 255
|
24
|
+
x_test /= 255
|
25
|
+
|
26
|
+
y_train = DNN::Utils.to_categorical(y_train, 10, Numo::SFloat)
|
27
|
+
y_test = DNN::Utils.to_categorical(y_test, 10, Numo::SFloat)
|
28
|
+
|
29
|
+
class MLP < Model
|
30
|
+
def initialize
|
31
|
+
super
|
32
|
+
# Set L2 regularizer(weight decay) for weight and bias.
|
33
|
+
@l1 = Dense.new(256, weight_regularizer: L2.new(L2_LAMBDA), bias_regularizer: L2.new(L2_LAMBDA))
|
34
|
+
@l2 = Dense.new(256, weight_regularizer: L2.new(L2_LAMBDA), bias_regularizer: L2.new(L2_LAMBDA))
|
35
|
+
@l3 = Dense.new(10, weight_regularizer: L2.new(L2_LAMBDA), bias_regularizer: L2.new(L2_LAMBDA))
|
36
|
+
@bn1 = BatchNormalization.new
|
37
|
+
@bn2 = BatchNormalization.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def call(x)
|
41
|
+
x = InputLayer.(x)
|
42
|
+
x = @l1.(x)
|
43
|
+
x = @bn1.(x)
|
44
|
+
x = ReLU.(x)
|
45
|
+
x = @l2.(x)
|
46
|
+
x = @bn2.(x)
|
47
|
+
x = ReLU.(x)
|
48
|
+
x = @l3.(x)
|
49
|
+
x
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
model = MLP.new
|
54
|
+
model.setup(Adam.new, SoftmaxCrossEntropy.new)
|
55
|
+
model.train(x_train, y_train, EPOCHS, batch_size: BATCH_SIZE, test: [x_test, y_test])
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require "dnn"
|
2
|
+
require "dnn/datasets/mnist"
|
3
|
+
# If you use numo/linalg then please uncomment out.
|
4
|
+
# require "numo/linalg/autoloader"
|
5
|
+
|
6
|
+
include DNN::Models
|
7
|
+
include DNN::Layers
|
8
|
+
include DNN::Optimizers
|
9
|
+
include DNN::Losses
|
10
|
+
include DNN::Savers
|
11
|
+
include DNN::Loaders
|
12
|
+
MNIST = DNN::MNIST
|
13
|
+
|
14
|
+
USE_MARSHAL = 0
|
15
|
+
USE_JSON = 1
|
16
|
+
|
17
|
+
EPOCHS = 3
|
18
|
+
BATCH_SIZE = 128
|
19
|
+
|
20
|
+
# Select save style from USE_MARSHAL or USE_JSON.
|
21
|
+
SAVE_STYLE = USE_MARSHAL
|
22
|
+
|
23
|
+
# When set a true, save data included optimizer status.
|
24
|
+
# This setting is enabled when SAVE_STYLE is USE_MARSHAL.
|
25
|
+
INCLUDE_OPTIMIZER = false
|
26
|
+
|
27
|
+
x_train, y_train = MNIST.load_train
|
28
|
+
x_test, y_test = MNIST.load_test
|
29
|
+
|
30
|
+
x_train = Numo::SFloat.cast(x_train).reshape(x_train.shape[0], 784)
|
31
|
+
x_test = Numo::SFloat.cast(x_test).reshape(x_test.shape[0], 784)
|
32
|
+
|
33
|
+
x_train /= 255
|
34
|
+
x_test /= 255
|
35
|
+
|
36
|
+
y_train = DNN::Utils.to_categorical(y_train, 10, Numo::SFloat)
|
37
|
+
y_test = DNN::Utils.to_categorical(y_test, 10, Numo::SFloat)
|
38
|
+
|
39
|
+
class MLP < Model
|
40
|
+
def initialize
|
41
|
+
super
|
42
|
+
@l1 = Dense.new(256)
|
43
|
+
@l2 = Dense.new(256)
|
44
|
+
@l3 = Dense.new(10)
|
45
|
+
@bn1 = BatchNormalization.new
|
46
|
+
@bn2 = BatchNormalization.new
|
47
|
+
end
|
48
|
+
|
49
|
+
def call(x)
|
50
|
+
x = InputLayer.(x)
|
51
|
+
x = @l1.(x)
|
52
|
+
x = @bn1.(x)
|
53
|
+
x = ReLU.(x)
|
54
|
+
x = @l2.(x)
|
55
|
+
x = @bn2.(x)
|
56
|
+
x = ReLU.(x)
|
57
|
+
x = @l3.(x)
|
58
|
+
x
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
model = MLP.new
|
63
|
+
model.setup(Adam.new, SoftmaxCrossEntropy.new)
|
64
|
+
model.train(x_train, y_train, EPOCHS, batch_size: BATCH_SIZE, test: [x_test, y_test])
|
65
|
+
|
66
|
+
if SAVE_STYLE == USE_MARSHAL
|
67
|
+
saver = MarshalSaver.new(model, include_optimizer: INCLUDE_OPTIMIZER)
|
68
|
+
saver.save("trained_mnist.marshal")
|
69
|
+
# model.save("trained_mnist.marshal") # This code is equivalent to the code above.
|
70
|
+
elsif SAVE_STYLE == USE_JSON
|
71
|
+
saver = JSONSaver.new(model)
|
72
|
+
saver.save("trained_mnist.json")
|
73
|
+
end
|
74
|
+
|
75
|
+
model2 = MLP.new
|
76
|
+
if SAVE_STYLE == USE_MARSHAL
|
77
|
+
loader = MarshalLoader.new(model2)
|
78
|
+
loader.load("trained_mnist.marshal")
|
79
|
+
# MLP.load("trained_mnist.marshal") # This code is equivalent to the code above.
|
80
|
+
elsif SAVE_STYLE == USE_JSON
|
81
|
+
loader = JSONLoader.new(model2)
|
82
|
+
loader.load("trained_mnist.json")
|
83
|
+
end
|
84
|
+
|
85
|
+
puts model2.accuracy(x_test, y_test)
|
data/lib/dnn/core/callbacks.rb
CHANGED
@@ -65,7 +65,7 @@ module DNN
|
|
65
65
|
def judge_early_stopping_train
|
66
66
|
case @trigger
|
67
67
|
when :train_loss
|
68
|
-
return true if model.last_log[@trigger]
|
68
|
+
return true if model.last_log[@trigger] <= @tolerance
|
69
69
|
end
|
70
70
|
false
|
71
71
|
end
|
@@ -73,7 +73,7 @@ module DNN
|
|
73
73
|
def judge_early_stopping_test
|
74
74
|
case @trigger
|
75
75
|
when :test_loss
|
76
|
-
return true if model.last_log[@trigger]
|
76
|
+
return true if model.last_log[@trigger] <= @tolerance
|
77
77
|
when :test_accuracy
|
78
78
|
return true if model.last_log[@trigger] >= @tolerance
|
79
79
|
end
|
data/lib/dnn/core/layers.rb
CHANGED
@@ -97,8 +97,9 @@ module DNN
|
|
97
97
|
end
|
98
98
|
|
99
99
|
class InputLayer < Layer
|
100
|
-
def self.call(
|
101
|
-
|
100
|
+
def self.call(input)
|
101
|
+
shape = input.is_a?(Tensor) ? input.data.shape : input.shape
|
102
|
+
new(shape[1..-1]).(input)
|
102
103
|
end
|
103
104
|
|
104
105
|
# @param [Array] input_dim_or_shape Setting the shape or dimension of the input data.
|
@@ -107,9 +108,16 @@ module DNN
|
|
107
108
|
@input_shape = input_dim_or_shape.is_a?(Array) ? input_dim_or_shape : [input_dim_or_shape]
|
108
109
|
end
|
109
110
|
|
110
|
-
def call(
|
111
|
+
def call(input)
|
111
112
|
build unless built?
|
112
|
-
|
113
|
+
if input.is_a?(Tensor)
|
114
|
+
x = input.data
|
115
|
+
prev_link = input&.link
|
116
|
+
else
|
117
|
+
x = input
|
118
|
+
prev_link = nil
|
119
|
+
end
|
120
|
+
Tensor.new(forward(x), Link.new(prev_link, self))
|
113
121
|
end
|
114
122
|
|
115
123
|
def build
|
@@ -333,7 +341,7 @@ module DNN
|
|
333
341
|
def forward(x)
|
334
342
|
if DNN.learning_phase
|
335
343
|
Xumo::SFloat.srand(@rnd.rand(1 << 31))
|
336
|
-
@mask = Xumo::SFloat.
|
344
|
+
@mask = Xumo::SFloat.new(*x.shape).rand < @dropout_ratio
|
337
345
|
x[@mask] = 0
|
338
346
|
elsif @use_scale
|
339
347
|
x *= (1 - @dropout_ratio)
|
data/lib/dnn/core/losses.rb
CHANGED
data/lib/dnn/core/models.rb
CHANGED
@@ -135,7 +135,7 @@ module DNN
|
|
135
135
|
# @return [Hash] Hash of contents to be output to log.
|
136
136
|
private def train_step(x, y)
|
137
137
|
loss_value = train_on_batch(x, y)
|
138
|
-
{ loss: loss_value
|
138
|
+
{ loss: loss_value }
|
139
139
|
end
|
140
140
|
|
141
141
|
# Implement the test process to be performed.
|
@@ -185,7 +185,7 @@ module DNN
|
|
185
185
|
iter.foreach(batch_size) do |x_batch, y_batch|
|
186
186
|
correct, loss_value = test_on_batch(x_batch, y_batch)
|
187
187
|
total_correct += correct
|
188
|
-
sum_loss += loss_value
|
188
|
+
sum_loss += loss_value
|
189
189
|
end
|
190
190
|
mean_loss = sum_loss / max_steps
|
191
191
|
acc = total_correct.to_f / num_test_datas
|
@@ -259,8 +259,9 @@ module DNN
|
|
259
259
|
|
260
260
|
# Save the model in marshal format.
|
261
261
|
# @param [String] file_name Name to save model.
|
262
|
-
|
263
|
-
|
262
|
+
# @param [Boolean] include_optimizer Set true to save data included optimizer status.
|
263
|
+
def save(file_name, include_optimizer: true)
|
264
|
+
saver = Savers::MarshalSaver.new(self, include_optimizer: include_optimizer)
|
264
265
|
saver.save(file_name)
|
265
266
|
end
|
266
267
|
|
@@ -312,7 +313,12 @@ module DNN
|
|
312
313
|
def forward(x, learning_phase)
|
313
314
|
DNN.learning_phase = learning_phase
|
314
315
|
@layers_cache = nil
|
315
|
-
|
316
|
+
inputs = if x.is_a?(Array)
|
317
|
+
x.map { |a| Tensor.new(a, nil) }
|
318
|
+
else
|
319
|
+
Tensor.new(x, nil)
|
320
|
+
end
|
321
|
+
output_tensor = call(inputs)
|
316
322
|
@last_link = output_tensor.link
|
317
323
|
unless @built
|
318
324
|
@built = true
|
data/lib/dnn/image.rb
CHANGED
@@ -18,9 +18,9 @@ module DNN
|
|
18
18
|
# @param [String] file_name File name to read.
|
19
19
|
# @param [Integer] channel_type Specify channel type of image.
|
20
20
|
def self.read(file_name, channel_type = RGB)
|
21
|
-
raise ImageReadError
|
21
|
+
raise ImageReadError, "#{file_name} is not found." unless File.exist?(file_name)
|
22
22
|
bin, w, h, n = Stb.stbi_load(file_name, channel_type)
|
23
|
-
raise ImageReadError
|
23
|
+
raise ImageReadError, "#{file_name} load failed." if bin == ""
|
24
24
|
img = Numo::UInt8.from_binary(bin)
|
25
25
|
img.reshape(h, w, channel_type)
|
26
26
|
end
|
@@ -38,18 +38,26 @@ module DNN
|
|
38
38
|
end
|
39
39
|
h, w, ch = img.shape
|
40
40
|
bin = img.to_binary
|
41
|
-
|
42
|
-
|
41
|
+
match_data = file_name.match(/\.(\w+)$/i)
|
42
|
+
if match_data
|
43
|
+
ext = match_data[1]
|
44
|
+
else
|
45
|
+
raise ImageWriteError, "File name has not extension."
|
46
|
+
end
|
47
|
+
case ext
|
48
|
+
when "png"
|
43
49
|
stride_in_bytes = w * ch
|
44
50
|
res = Stb.stbi_write_png(file_name, w, h, ch, bin, stride_in_bytes)
|
45
|
-
when
|
51
|
+
when "bmp"
|
46
52
|
res = Stb.stbi_write_bmp(file_name, w, h, ch, bin)
|
47
|
-
when
|
53
|
+
when "jpg", "jpeg"
|
48
54
|
raise TypeError, "quality:#{quality.class} is not an instance of Integer class." unless quality.is_a?(Integer)
|
49
55
|
raise ArgumentError, "quality should be between 1 and 100." unless quality.between?(1, 100)
|
50
56
|
res = Stb.stbi_write_jpg(file_name, w, h, ch, bin, quality)
|
57
|
+
else
|
58
|
+
raise ImageWriteError, "Extension '#{ext}' is not support."
|
51
59
|
end
|
52
|
-
raise ImageWriteError
|
60
|
+
raise ImageWriteError, "Image write failed." if res == 0
|
53
61
|
end
|
54
62
|
|
55
63
|
# Resize the image.
|
@@ -90,11 +98,11 @@ module DNN
|
|
90
98
|
end
|
91
99
|
|
92
100
|
private_class_method def self.img_check(img)
|
93
|
-
raise TypeError
|
101
|
+
raise TypeError, "img: #{img.class} is not an instance of the Numo::UInt8 class." unless img.is_a?(Numo::UInt8)
|
94
102
|
if img.shape.length != 3
|
95
|
-
raise ImageShapeError
|
103
|
+
raise ImageShapeError, "img shape is #{img.shape}. But img shape must be 3 dimensional."
|
96
104
|
elsif !img.shape[2].between?(1, 4)
|
97
|
-
raise ImageShapeError
|
105
|
+
raise ImageShapeError, "img channel is #{img.shape[2]}. But img channel must be 1 or 2 or 3 or 4."
|
98
106
|
end
|
99
107
|
end
|
100
108
|
end
|
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: 0.14.
|
4
|
+
version: 0.14.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- unagiootoro
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-10-
|
11
|
+
date: 2019-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: numo-narray
|
@@ -98,6 +98,10 @@ files:
|
|
98
98
|
- Rakefile
|
99
99
|
- bin/console
|
100
100
|
- bin/setup
|
101
|
+
- examples/api-examples/early_stopping_example.rb
|
102
|
+
- examples/api-examples/initializer_example.rb
|
103
|
+
- examples/api-examples/regularizer_example.rb
|
104
|
+
- examples/api-examples/save_example.rb
|
101
105
|
- examples/cifar100_example.rb
|
102
106
|
- examples/cifar10_example.rb
|
103
107
|
- examples/dcgan/dcgan.rb
|