ruby-dnn 0.16.2 → 1.0.0
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 +22 -0
- data/examples/api-examples/early_stopping_example.rb +1 -1
- data/examples/api-examples/initializer_example.rb +1 -1
- data/examples/api-examples/regularizer_example.rb +1 -1
- data/examples/dcgan/dcgan.rb +10 -3
- data/examples/pix2pix/dcgan.rb +4 -0
- data/examples/pix2pix/train.rb +5 -2
- data/examples/vae.rb +0 -6
- data/lib/dnn/core/callbacks.rb +7 -3
- data/lib/dnn/core/error.rb +2 -2
- data/lib/dnn/core/initializers.rb +5 -5
- data/lib/dnn/core/iterator.rb +4 -1
- data/lib/dnn/core/layers/basic_layers.rb +42 -65
- data/lib/dnn/core/layers/cnn_layers.rb +34 -35
- data/lib/dnn/core/layers/embedding.rb +3 -24
- data/lib/dnn/core/layers/math_layers.rb +12 -0
- data/lib/dnn/core/layers/merge_layers.rb +13 -13
- data/lib/dnn/core/layers/normalizations.rb +4 -4
- data/lib/dnn/core/layers/rnn_layers.rb +46 -46
- data/lib/dnn/core/link.rb +8 -8
- data/lib/dnn/core/losses.rb +10 -20
- data/lib/dnn/core/models.rb +23 -46
- data/lib/dnn/core/monkey_patch.rb +10 -0
- data/lib/dnn/core/optimizers.rb +1 -2
- data/lib/dnn/core/param.rb +2 -2
- data/lib/dnn/core/regularizers.rb +1 -1
- data/lib/dnn/core/savers.rb +2 -2
- data/lib/dnn/core/tensor.rb +1 -1
- data/lib/dnn/datasets/cifar10.rb +1 -1
- data/lib/dnn/datasets/cifar100.rb +1 -1
- data/lib/dnn/datasets/downloader.rb +1 -1
- data/lib/dnn/datasets/fashion-mnist.rb +1 -1
- data/lib/dnn/datasets/iris.rb +1 -1
- data/lib/dnn/datasets/mnist.rb +1 -1
- data/lib/dnn/datasets/stl-10.rb +2 -2
- data/lib/dnn/version.rb +1 -1
- metadata +2 -2
data/lib/dnn/core/link.rb
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
module DNN
|
|
2
2
|
class Link
|
|
3
3
|
attr_accessor :prev
|
|
4
|
-
attr_accessor :
|
|
4
|
+
attr_accessor :layer_node
|
|
5
5
|
|
|
6
|
-
def initialize(prev = nil,
|
|
6
|
+
def initialize(prev = nil, layer_node = nil)
|
|
7
7
|
@prev = prev
|
|
8
|
-
@
|
|
8
|
+
@layer_node = layer_node
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def backward(dy = Numo::SFloat[1])
|
|
12
|
-
dy = @
|
|
12
|
+
dy = @layer_node.backward_node(dy)
|
|
13
13
|
@prev&.backward(dy)
|
|
14
14
|
end
|
|
15
15
|
end
|
|
@@ -17,16 +17,16 @@ module DNN
|
|
|
17
17
|
class TwoInputLink
|
|
18
18
|
attr_accessor :prev1
|
|
19
19
|
attr_accessor :prev2
|
|
20
|
-
attr_accessor :
|
|
20
|
+
attr_accessor :layer_node
|
|
21
21
|
|
|
22
|
-
def initialize(prev1 = nil, prev2 = nil,
|
|
22
|
+
def initialize(prev1 = nil, prev2 = nil, layer_node = nil)
|
|
23
23
|
@prev1 = prev1
|
|
24
24
|
@prev2 = prev2
|
|
25
|
-
@
|
|
25
|
+
@layer_node = layer_node
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def backward(dy = Numo::SFloat[1])
|
|
29
|
-
dys = @
|
|
29
|
+
dys = @layer_node.backward_node(dy)
|
|
30
30
|
if dys.is_a?(Array)
|
|
31
31
|
dy1, dy2 = *dys
|
|
32
32
|
else
|
data/lib/dnn/core/losses.rb
CHANGED
|
@@ -10,7 +10,7 @@ module DNN
|
|
|
10
10
|
return nil unless hash
|
|
11
11
|
loss_class = DNN.const_get(hash[:class])
|
|
12
12
|
loss = loss_class.allocate
|
|
13
|
-
raise
|
|
13
|
+
raise DNNError, "#{loss.class} is not an instance of #{self} class." unless loss.is_a?(self)
|
|
14
14
|
loss.load_hash(hash)
|
|
15
15
|
loss
|
|
16
16
|
end
|
|
@@ -21,7 +21,7 @@ module DNN
|
|
|
21
21
|
|
|
22
22
|
def loss(y, t, layers = nil)
|
|
23
23
|
unless y.shape == t.shape
|
|
24
|
-
raise
|
|
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
27
|
loss = regularizers_forward(loss, layers) if layers
|
|
@@ -76,7 +76,7 @@ module DNN
|
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def backward_node(d)
|
|
79
|
-
(@y - @t) / @y.shape[0]
|
|
79
|
+
d * (@y - @t) / @y.shape[0]
|
|
80
80
|
end
|
|
81
81
|
end
|
|
82
82
|
|
|
@@ -93,7 +93,7 @@ module DNN
|
|
|
93
93
|
dy = (@y - @t)
|
|
94
94
|
dy[dy >= 0] = 1
|
|
95
95
|
dy[dy < 0] = -1
|
|
96
|
-
dy / @y.shape[0]
|
|
96
|
+
d * dy / @y.shape[0]
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
99
|
|
|
@@ -109,7 +109,7 @@ module DNN
|
|
|
109
109
|
def backward_node(d)
|
|
110
110
|
a = Xumo::SFloat.ones(*@a.shape)
|
|
111
111
|
a[@a <= 0] = 0
|
|
112
|
-
(a * -@t) / a.shape[0]
|
|
112
|
+
d * (a * -@t) / a.shape[0]
|
|
113
113
|
end
|
|
114
114
|
end
|
|
115
115
|
|
|
@@ -119,8 +119,8 @@ module DNN
|
|
|
119
119
|
def forward_node(y, t)
|
|
120
120
|
@y = y
|
|
121
121
|
@t = t
|
|
122
|
-
loss_l1_value =
|
|
123
|
-
@loss_value = loss_l1_value > 1 ? loss_l1_value :
|
|
122
|
+
loss_l1_value = (y - t).abs.mean(0).sum
|
|
123
|
+
@loss_value = loss_l1_value > 1 ? loss_l1_value : 0.5 * ((y - t)**2).mean(0).sum
|
|
124
124
|
end
|
|
125
125
|
|
|
126
126
|
def backward_node(d)
|
|
@@ -129,17 +129,7 @@ module DNN
|
|
|
129
129
|
dy[dy >= 0] = 1
|
|
130
130
|
dy[dy < 0] = -1
|
|
131
131
|
end
|
|
132
|
-
dy / @y.shape[0]
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
private
|
|
136
|
-
|
|
137
|
-
def loss_l1(y, t)
|
|
138
|
-
(y - t).abs.mean(0).sum
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def loss_l2(y, t)
|
|
142
|
-
0.5 * ((y - t)**2).mean(0).sum
|
|
132
|
+
d * dy / @y.shape[0]
|
|
143
133
|
end
|
|
144
134
|
end
|
|
145
135
|
|
|
@@ -168,7 +158,7 @@ module DNN
|
|
|
168
158
|
end
|
|
169
159
|
|
|
170
160
|
def backward_node(d)
|
|
171
|
-
(@x - @t) / @x.shape[0]
|
|
161
|
+
d * (@x - @t) / @x.shape[0]
|
|
172
162
|
end
|
|
173
163
|
|
|
174
164
|
def to_hash
|
|
@@ -205,7 +195,7 @@ module DNN
|
|
|
205
195
|
end
|
|
206
196
|
|
|
207
197
|
def backward_node(d)
|
|
208
|
-
(@x - @t) / @x.shape[0]
|
|
198
|
+
d * (@x - @t) / @x.shape[0]
|
|
209
199
|
end
|
|
210
200
|
|
|
211
201
|
def to_hash
|
data/lib/dnn/core/models.rb
CHANGED
|
@@ -39,23 +39,28 @@ module DNN
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
class Chain
|
|
42
|
+
def initialize
|
|
43
|
+
@layers_cache = nil
|
|
44
|
+
end
|
|
45
|
+
|
|
42
46
|
# Forward propagation.
|
|
43
|
-
# @param [Tensor]
|
|
47
|
+
# @param [Tensor] input_tensors Input tensors.
|
|
44
48
|
# @return [Tensor] Output tensor.
|
|
45
|
-
def forward(
|
|
49
|
+
def forward(input_tensors)
|
|
46
50
|
raise NotImplementedError, "Class '#{self.class.name}' has implement method 'forward'"
|
|
47
51
|
end
|
|
48
52
|
|
|
49
53
|
# Forward propagation and create a link.
|
|
50
|
-
# @param [Tensor]
|
|
54
|
+
# @param [Tensor | Array] input_tensors Input tensors.
|
|
51
55
|
# @return [Tensor] Output tensor.
|
|
52
|
-
def call(
|
|
53
|
-
forward(
|
|
56
|
+
def call(input_tensors)
|
|
57
|
+
forward(input_tensors)
|
|
54
58
|
end
|
|
55
59
|
|
|
56
60
|
# Get the all layers.
|
|
57
61
|
# @return [Array] All layers array.
|
|
58
62
|
def layers
|
|
63
|
+
return @layers_cache if @layers_cache
|
|
59
64
|
layers_array = []
|
|
60
65
|
instance_variables.sort.each do |ivar|
|
|
61
66
|
obj = instance_variable_get(ivar)
|
|
@@ -65,39 +70,7 @@ module DNN
|
|
|
65
70
|
layers_array.concat(obj.layers)
|
|
66
71
|
end
|
|
67
72
|
end
|
|
68
|
-
layers_array
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def to_hash
|
|
72
|
-
layers_hash = { class: self.class.name }
|
|
73
|
-
instance_variables.sort.each do |ivar|
|
|
74
|
-
obj = instance_variable_get(ivar)
|
|
75
|
-
if obj.is_a?(Layers::Layer) || obj.is_a?(Chain)
|
|
76
|
-
layers_hash[ivar] = obj.to_hash
|
|
77
|
-
elsif obj.is_a?(LayersList)
|
|
78
|
-
layers_hash[ivar] = obj.to_hash_list
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
layers_hash
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def load_hash(layers_hash)
|
|
85
|
-
instance_variables.sort.each do |ivar|
|
|
86
|
-
hash_or_array = layers_hash[ivar]
|
|
87
|
-
if hash_or_array.is_a?(Array)
|
|
88
|
-
instance_variable_set(ivar, LayersList.from_hash_list(hash_or_array))
|
|
89
|
-
elsif hash_or_array.is_a?(Hash)
|
|
90
|
-
obj_class = DNN.const_get(hash_or_array[:class])
|
|
91
|
-
obj = obj_class.allocate
|
|
92
|
-
if obj.is_a?(Chain)
|
|
93
|
-
obj = obj_class.new
|
|
94
|
-
obj.load_hash(hash_or_array)
|
|
95
|
-
instance_variable_set(ivar, obj)
|
|
96
|
-
else
|
|
97
|
-
instance_variable_set(ivar, Layers::Layer.from_hash(hash_or_array))
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
|
73
|
+
@layers_cache = layers_array
|
|
101
74
|
end
|
|
102
75
|
end
|
|
103
76
|
|
|
@@ -118,17 +91,16 @@ module DNN
|
|
|
118
91
|
end
|
|
119
92
|
|
|
120
93
|
def initialize
|
|
94
|
+
super
|
|
121
95
|
@optimizer = nil
|
|
122
96
|
@loss_func = nil
|
|
123
97
|
@built = false
|
|
124
98
|
@callbacks = []
|
|
125
|
-
@layers_cache = nil
|
|
126
99
|
@last_log = {}
|
|
127
100
|
end
|
|
128
101
|
|
|
129
|
-
def call(
|
|
130
|
-
|
|
131
|
-
output_tensor = forward(inputs)
|
|
102
|
+
def call(input_tensors)
|
|
103
|
+
output_tensor = forward(input_tensors)
|
|
132
104
|
@built = true unless @built
|
|
133
105
|
output_tensor
|
|
134
106
|
end
|
|
@@ -187,8 +159,8 @@ module DNN
|
|
|
187
159
|
initial_epoch: 1,
|
|
188
160
|
test: nil,
|
|
189
161
|
verbose: true)
|
|
190
|
-
raise
|
|
191
|
-
raise
|
|
162
|
+
raise DNNError, "The model is not optimizer setup complete." unless @optimizer
|
|
163
|
+
raise DNNError, "The model is not loss_func setup complete." unless @loss_func
|
|
192
164
|
|
|
193
165
|
num_train_datas = train_iterator.num_datas
|
|
194
166
|
num_train_datas = num_train_datas / batch_size * batch_size if train_iterator.last_round_down
|
|
@@ -255,8 +227,8 @@ module DNN
|
|
|
255
227
|
# @param [Numo::SFloat] y Output training data.
|
|
256
228
|
# @return [Float | Numo::SFloat] Return loss value in the form of Float or Numo::SFloat.
|
|
257
229
|
def train_on_batch(x, y)
|
|
258
|
-
raise
|
|
259
|
-
raise
|
|
230
|
+
raise DNNError, "The model is not optimizer setup complete." unless @optimizer
|
|
231
|
+
raise DNNError, "The model is not loss_func setup complete." unless @loss_func
|
|
260
232
|
check_xy_type(x, y)
|
|
261
233
|
call_callbacks(:before_train_on_batch)
|
|
262
234
|
DNN.learning_phase = true
|
|
@@ -419,12 +391,15 @@ module DNN
|
|
|
419
391
|
@built
|
|
420
392
|
end
|
|
421
393
|
|
|
394
|
+
# Clean all layers.
|
|
422
395
|
def clean_layers
|
|
423
396
|
layers.each(&:clean)
|
|
424
397
|
@loss_func.clean
|
|
425
398
|
@layers_cache = nil
|
|
426
399
|
end
|
|
427
400
|
|
|
401
|
+
# Get parameter data of all layers.
|
|
402
|
+
# @return [Array] Parameter data.
|
|
428
403
|
def get_all_params_data
|
|
429
404
|
trainable_layers.map do |layer|
|
|
430
405
|
layer.get_params.to_h do |key, param|
|
|
@@ -433,6 +408,8 @@ module DNN
|
|
|
433
408
|
end
|
|
434
409
|
end
|
|
435
410
|
|
|
411
|
+
# Set parameter data of all layers.
|
|
412
|
+
# @param [Array] params_data Parameter data obtained by get_all_params_data.
|
|
436
413
|
def set_all_params_data(params_data)
|
|
437
414
|
trainable_layers.each.with_index do |layer, i|
|
|
438
415
|
params_data[i].each do |(key, data)|
|
data/lib/dnn/core/optimizers.rb
CHANGED
|
@@ -9,7 +9,7 @@ module DNN
|
|
|
9
9
|
return nil unless hash
|
|
10
10
|
optimizer_class = DNN.const_get(hash[:class])
|
|
11
11
|
optimizer = optimizer_class.allocate
|
|
12
|
-
raise
|
|
12
|
+
raise DNNError, "#{optimizer.class} is not an instance of #{self} class." unless optimizer.is_a?(self)
|
|
13
13
|
optimizer.load_hash(hash)
|
|
14
14
|
optimizer
|
|
15
15
|
end
|
|
@@ -49,7 +49,6 @@ module DNN
|
|
|
49
49
|
private def clip_grads(params)
|
|
50
50
|
norm = Math.sqrt(params.reduce(0) { |total, param| total + (param.grad**2).sum })
|
|
51
51
|
return if norm <= @clip_norm
|
|
52
|
-
|
|
53
52
|
rate = @clip_norm / (norm + 1e-7)
|
|
54
53
|
params.each do |param|
|
|
55
54
|
param.grad *= rate
|
data/lib/dnn/core/param.rb
CHANGED
|
@@ -18,7 +18,7 @@ module DNN
|
|
|
18
18
|
elsif @data.shape == grad.shape[1..-1]
|
|
19
19
|
@grad += grad.sum(0)
|
|
20
20
|
else
|
|
21
|
-
raise
|
|
21
|
+
raise DNNError, "Shape is missmatch."
|
|
22
22
|
end
|
|
23
23
|
else
|
|
24
24
|
@grad = Xumo::SFloat[0]
|
|
@@ -34,7 +34,7 @@ module DNN
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def -@
|
|
37
|
-
self
|
|
37
|
+
Neg.(self)
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def +(other)
|
|
@@ -8,7 +8,7 @@ module DNN
|
|
|
8
8
|
return nil unless hash
|
|
9
9
|
regularizer_class = DNN.const_get(hash[:class])
|
|
10
10
|
regularizer = regularizer_class.allocate
|
|
11
|
-
raise
|
|
11
|
+
raise DNNError, "#{regularizer.class} is not an instance of #{self} class." unless regularizer.is_a?(self)
|
|
12
12
|
regularizer.load_hash(hash)
|
|
13
13
|
regularizer
|
|
14
14
|
end
|
data/lib/dnn/core/savers.rb
CHANGED
|
@@ -25,7 +25,7 @@ module DNN
|
|
|
25
25
|
private def load_bin(bin)
|
|
26
26
|
data = Marshal.load(Zlib::Inflate.inflate(bin))
|
|
27
27
|
unless @model.class.name == data[:class]
|
|
28
|
-
raise
|
|
28
|
+
raise DNNError, "Class name is mismatch. Target model is #{@model.class.name}. But loading model is #{data[:class]}."
|
|
29
29
|
end
|
|
30
30
|
if data[:model]
|
|
31
31
|
data[:model].instance_variables.each do |ivar|
|
|
@@ -43,7 +43,7 @@ module DNN
|
|
|
43
43
|
def load_bin(bin)
|
|
44
44
|
data = JSON.parse(bin, symbolize_names: true)
|
|
45
45
|
unless @model.class.name == data[:class]
|
|
46
|
-
raise
|
|
46
|
+
raise DNNError, "Class name is mismatch. Target model is #{@model.class.name}. But loading model is #{data[:class]}."
|
|
47
47
|
end
|
|
48
48
|
set_all_params_base64_data(data[:params])
|
|
49
49
|
end
|
data/lib/dnn/core/tensor.rb
CHANGED
data/lib/dnn/datasets/cifar10.rb
CHANGED
data/lib/dnn/datasets/iris.rb
CHANGED
data/lib/dnn/datasets/mnist.rb
CHANGED
data/lib/dnn/datasets/stl-10.rb
CHANGED
|
@@ -7,7 +7,7 @@ DIR_STL10 = "stl10_binary"
|
|
|
7
7
|
|
|
8
8
|
module DNN
|
|
9
9
|
module STL10
|
|
10
|
-
class DNN_STL10_LoadError <
|
|
10
|
+
class DNN_STL10_LoadError < DNNError; end
|
|
11
11
|
|
|
12
12
|
def self.downloads
|
|
13
13
|
return if Dir.exist?(DOWNLOADS_PATH + "/downloads/" + DIR_STL10)
|
|
@@ -49,7 +49,7 @@ module DNN
|
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def self.load_unlabeled(range = 0...100000)
|
|
52
|
-
raise
|
|
52
|
+
raise DNNError, "Range must between 0 and 100000. (But the end is excluded)" unless range.begin >= 0 && range.end <= 100000
|
|
53
53
|
downloads
|
|
54
54
|
x_fname = DOWNLOADS_PATH + "/downloads/#{DIR_STL10}/unlabeled_X.bin"
|
|
55
55
|
raise DNN_STL10_LoadError, %`file "#{x_fname}" is not found.` unless File.exist?(x_fname)
|
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.
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- unagiootoro
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-01-
|
|
11
|
+
date: 2020-01-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: numo-narray
|