ruby-dnn 0.10.4 → 0.12.4
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/.travis.yml +1 -2
- data/README.md +33 -6
- data/examples/cifar100_example.rb +3 -3
- data/examples/cifar10_example.rb +3 -3
- data/examples/dcgan/dcgan.rb +112 -0
- data/examples/dcgan/imgen.rb +20 -0
- data/examples/dcgan/train.rb +41 -0
- data/examples/iris_example.rb +3 -6
- data/examples/mnist_conv2d_example.rb +5 -5
- data/examples/mnist_define_by_run.rb +52 -0
- data/examples/mnist_example.rb +3 -3
- data/examples/mnist_lstm_example.rb +3 -3
- data/examples/xor_example.rb +4 -5
- data/ext/rb_stb_image/rb_stb_image.c +103 -0
- data/lib/dnn.rb +10 -10
- data/lib/dnn/cifar10.rb +1 -1
- data/lib/dnn/cifar100.rb +1 -1
- data/lib/dnn/core/activations.rb +21 -22
- data/lib/dnn/core/cnn_layers.rb +94 -111
- data/lib/dnn/core/embedding.rb +30 -9
- data/lib/dnn/core/initializers.rb +31 -21
- data/lib/dnn/core/iterator.rb +52 -0
- data/lib/dnn/core/layers.rb +99 -66
- data/lib/dnn/core/link.rb +24 -0
- data/lib/dnn/core/losses.rb +69 -59
- data/lib/dnn/core/merge_layers.rb +71 -0
- data/lib/dnn/core/models.rb +393 -0
- data/lib/dnn/core/normalizations.rb +27 -14
- data/lib/dnn/core/optimizers.rb +212 -134
- data/lib/dnn/core/param.rb +8 -6
- data/lib/dnn/core/regularizers.rb +10 -7
- data/lib/dnn/core/rnn_layers.rb +78 -85
- data/lib/dnn/core/utils.rb +6 -3
- data/lib/dnn/downloader.rb +3 -3
- data/lib/dnn/fashion-mnist.rb +89 -0
- data/lib/dnn/image.rb +57 -18
- data/lib/dnn/iris.rb +1 -3
- data/lib/dnn/mnist.rb +38 -34
- data/lib/dnn/version.rb +1 -1
- data/third_party/stb_image.h +16 -4
- data/third_party/stb_image_resize.h +2630 -0
- data/third_party/stb_image_write.h +4 -7
- metadata +12 -4
- data/lib/dnn/core/dataset.rb +0 -34
- data/lib/dnn/core/model.rb +0 -440
data/lib/dnn/core/embedding.rb
CHANGED
@@ -2,30 +2,42 @@ module DNN
|
|
2
2
|
module Layers
|
3
3
|
|
4
4
|
class Embedding < HasParamLayer
|
5
|
-
# @return [Integer] Return the input length.
|
6
5
|
attr_reader :input_length
|
7
|
-
|
6
|
+
attr_reader :weight
|
8
7
|
attr_reader :weight_initializer
|
8
|
+
attr_reader :weight_regularizer
|
9
9
|
|
10
10
|
def self.from_hash(hash)
|
11
11
|
self.new(hash[:input_shape], hash[:input_length],
|
12
|
-
weight_initializer: DNN::Utils.
|
12
|
+
weight_initializer: DNN::Utils.hash_to_obj(hash[:weight_initializer]),
|
13
|
+
weight_regularizer: DNN::Utils.hash_to_obj(hash[:weight_regularizer]))
|
13
14
|
end
|
14
|
-
|
15
|
+
|
15
16
|
# @param [Integer | Array] input_dim_or_shape Set input data dimension or shape.
|
16
|
-
# @param [Integer] input_length
|
17
|
-
|
17
|
+
# @param [Integer] input_length Set the time series length of input data.
|
18
|
+
# @param [DNN::Initializers::Initializer] weight_initializer Weight initializer.
|
19
|
+
# @param [DNN::Regularizers::Regularizer | NilClass] weight_regularizer Weight regularizer.
|
20
|
+
def initialize(input_dim_or_shape, input_length,
|
21
|
+
weight_initializer: Initializers::RandomUniform.new,
|
22
|
+
weight_regularizer: nil)
|
18
23
|
super()
|
19
24
|
@input_shape = input_dim_or_shape.is_a?(Array) ? input_dim_or_shape : [input_dim_or_shape]
|
20
25
|
@input_length = input_length
|
21
26
|
@weight_initializer = weight_initializer
|
27
|
+
@weight_regularizer = weight_regularizer
|
28
|
+
end
|
29
|
+
|
30
|
+
def call(input)
|
31
|
+
x, *, learning_phase = *input
|
32
|
+
build unless built?
|
33
|
+
[forward(x), Link.new(nil, self), learning_phase]
|
22
34
|
end
|
23
35
|
|
24
36
|
def build
|
25
37
|
@built = true
|
26
|
-
@
|
38
|
+
@weight = Param.new(Xumo::SFloat.new(@input_length), 0)
|
27
39
|
@weight_initializer.init_param(self, @weight)
|
28
|
-
@
|
40
|
+
@weight_regularizer.param = @weight if @weight_regularizer
|
29
41
|
end
|
30
42
|
|
31
43
|
def forward(x)
|
@@ -47,8 +59,17 @@ module DNN
|
|
47
59
|
nil
|
48
60
|
end
|
49
61
|
|
62
|
+
def regularizers
|
63
|
+
@weight_regularizer ? [@weight_regularizer] : []
|
64
|
+
end
|
65
|
+
|
50
66
|
def to_hash
|
51
|
-
super(input_shape: @input_shape, input_length: @input_length,
|
67
|
+
super(input_shape: @input_shape, input_length: @input_length,
|
68
|
+
weight_initializer: @weight_initializer.to_hash, weight_regularizer: @weight_regularizer&.to_hash)
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_params
|
72
|
+
{ weight: @weight }
|
52
73
|
end
|
53
74
|
end
|
54
75
|
|
@@ -2,16 +2,21 @@ module DNN
|
|
2
2
|
module Initializers
|
3
3
|
|
4
4
|
class Initializer
|
5
|
-
|
5
|
+
# @param [Boolean | Integer] seed Seed of random number used for masking.
|
6
|
+
# Set true to determine seed as random.
|
7
|
+
def initialize(seed: false)
|
6
8
|
@seed = seed == true ? rand(1 << 31) : seed
|
7
9
|
end
|
8
10
|
|
11
|
+
# Initialization of learning parameters.
|
12
|
+
# @param [DNN::Layers::Layer] layer Layer that owns learning parameters.
|
13
|
+
# @param [DNN::Param] param Learning parameter to be initialized.
|
9
14
|
def init_param(layer, param)
|
10
|
-
raise NotImplementedError.new("Class '#{self.class.name}' has implement method '
|
15
|
+
raise NotImplementedError.new("Class '#{self.class.name}' has implement method 'init_param'")
|
11
16
|
end
|
12
17
|
|
13
18
|
def to_hash(merge_hash = nil)
|
14
|
-
hash = {class: self.class.name, seed: @seed}
|
19
|
+
hash = { class: self.class.name, seed: @seed }
|
15
20
|
hash.merge!(merge_hash) if merge_hash
|
16
21
|
hash
|
17
22
|
end
|
@@ -32,6 +37,7 @@ module DNN
|
|
32
37
|
self.new(hash[:const])
|
33
38
|
end
|
34
39
|
|
40
|
+
# @param [Float] const Constant value of initialization.
|
35
41
|
def initialize(const)
|
36
42
|
super()
|
37
43
|
@const = const
|
@@ -42,21 +48,23 @@ module DNN
|
|
42
48
|
end
|
43
49
|
|
44
50
|
def to_hash
|
45
|
-
super(
|
51
|
+
super(const: @const)
|
46
52
|
end
|
47
53
|
end
|
48
|
-
|
49
|
-
|
54
|
+
|
55
|
+
|
50
56
|
class RandomNormal < Initializer
|
51
57
|
attr_reader :mean
|
52
58
|
attr_reader :std
|
53
|
-
|
59
|
+
|
54
60
|
def self.from_hash(hash)
|
55
|
-
self.new(hash[:mean], hash[:std], hash[:seed])
|
61
|
+
self.new(hash[:mean], hash[:std], seed: hash[:seed])
|
56
62
|
end
|
57
63
|
|
58
|
-
|
59
|
-
|
64
|
+
# @param [Float] mean Average of initialization value.
|
65
|
+
# @param [Float] std Variance of initialization value.
|
66
|
+
def initialize(mean = 0, std = 0.05, seed: true)
|
67
|
+
super(seed: seed)
|
60
68
|
@mean = mean
|
61
69
|
@std = std
|
62
70
|
end
|
@@ -67,7 +75,7 @@ module DNN
|
|
67
75
|
end
|
68
76
|
|
69
77
|
def to_hash
|
70
|
-
super(
|
78
|
+
super(mean: @mean, std: @std)
|
71
79
|
end
|
72
80
|
end
|
73
81
|
|
@@ -77,11 +85,13 @@ module DNN
|
|
77
85
|
attr_reader :max
|
78
86
|
|
79
87
|
def self.from_hash(hash)
|
80
|
-
self.new(hash[:min], hash[:max], hash[:seed])
|
88
|
+
self.new(hash[:min], hash[:max], seed: hash[:seed])
|
81
89
|
end
|
82
90
|
|
83
|
-
|
84
|
-
|
91
|
+
# @param [Float] min Min of initialization value.
|
92
|
+
# @param [Float] max Max of initialization value.
|
93
|
+
def initialize(min = -0.05, max = 0.05, seed: true)
|
94
|
+
super(seed: seed)
|
85
95
|
@min = min
|
86
96
|
@max = max
|
87
97
|
end
|
@@ -92,13 +102,13 @@ module DNN
|
|
92
102
|
end
|
93
103
|
|
94
104
|
def to_hash
|
95
|
-
super(
|
105
|
+
super(min: @min, max: @max)
|
96
106
|
end
|
97
107
|
end
|
98
|
-
|
99
|
-
|
108
|
+
|
109
|
+
|
100
110
|
class Xavier < Initializer
|
101
|
-
def initialize(seed
|
111
|
+
def initialize(seed: true)
|
102
112
|
super
|
103
113
|
end
|
104
114
|
|
@@ -108,10 +118,10 @@ module DNN
|
|
108
118
|
param.data = param.data.rand_norm / Math.sqrt(num_prev_nodes)
|
109
119
|
end
|
110
120
|
end
|
111
|
-
|
112
|
-
|
121
|
+
|
122
|
+
|
113
123
|
class He < Initializer
|
114
|
-
def initialize(seed
|
124
|
+
def initialize(seed: true)
|
115
125
|
super
|
116
126
|
end
|
117
127
|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module DNN
|
2
|
+
# This class manages input datas and output datas together.
|
3
|
+
class Iterator
|
4
|
+
# @param [Numo::SFloat] x_datas input datas.
|
5
|
+
# @param [Numo::SFloat] y_datas output datas.
|
6
|
+
# @param [Boolean] random Set true to return batches randomly. Setting false returns batches in order of index.
|
7
|
+
def initialize(x_datas, y_datas, random: true)
|
8
|
+
@x_datas = x_datas
|
9
|
+
@y_datas = y_datas
|
10
|
+
@random = random
|
11
|
+
@num_datas = x_datas.shape[0]
|
12
|
+
reset
|
13
|
+
end
|
14
|
+
|
15
|
+
# Return the next batch.
|
16
|
+
# @param [Integer] batch_size Required batch size.
|
17
|
+
def next_batch(batch_size)
|
18
|
+
raise DNN_Error.new("This iterator has not next batch. Please call reset.") unless has_next?
|
19
|
+
if @indexes.length <= batch_size
|
20
|
+
batch_indexes = @indexes
|
21
|
+
@has_next = false
|
22
|
+
else
|
23
|
+
batch_indexes = @indexes.shift(batch_size)
|
24
|
+
end
|
25
|
+
x_batch = @x_datas[batch_indexes, false]
|
26
|
+
y_batch = @y_datas[batch_indexes, false]
|
27
|
+
[x_batch, y_batch]
|
28
|
+
end
|
29
|
+
|
30
|
+
# Reset input datas and output datas.
|
31
|
+
def reset
|
32
|
+
@has_next = true
|
33
|
+
@indexes = @num_datas.times.to_a
|
34
|
+
@indexes.shuffle! if @random
|
35
|
+
end
|
36
|
+
|
37
|
+
# Return the true if has next batch.
|
38
|
+
def has_next?
|
39
|
+
@has_next
|
40
|
+
end
|
41
|
+
|
42
|
+
def foreach(batch_size, &block)
|
43
|
+
step = 0
|
44
|
+
while has_next?
|
45
|
+
x_batch, y_batch = next_batch(batch_size)
|
46
|
+
block.call(x_batch, y_batch, step)
|
47
|
+
step += 1
|
48
|
+
end
|
49
|
+
reset
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/dnn/core/layers.rb
CHANGED
@@ -1,37 +1,48 @@
|
|
1
1
|
module DNN
|
2
2
|
module Layers
|
3
3
|
|
4
|
-
# Super class of all
|
4
|
+
# Super class of all layer classes.
|
5
5
|
class Layer
|
6
|
-
# @return [Bool] learning_phase Return the true if learning.
|
7
|
-
attr_accessor :learning_phase
|
8
|
-
# @return [Array] Return the shape of the input data.
|
9
6
|
attr_reader :input_shape
|
10
7
|
|
8
|
+
def self.call(x, *args)
|
9
|
+
self.new(*args).(x)
|
10
|
+
end
|
11
|
+
|
11
12
|
def initialize
|
12
13
|
@built = false
|
13
14
|
end
|
14
15
|
|
16
|
+
# Forward propagation and create a link.
|
17
|
+
# @param [Array] input Array of the form [x_input_data, prev_link, learning_phase].
|
18
|
+
def call(input)
|
19
|
+
x, prev_link, learning_phase = *input
|
20
|
+
build(x.shape[1..-1]) unless built?
|
21
|
+
y = forward(x)
|
22
|
+
link = Link.new(prev_link, self)
|
23
|
+
[y, link, learning_phase]
|
24
|
+
end
|
25
|
+
|
15
26
|
# Build the layer.
|
16
27
|
# @param [Array] input_shape Setting the shape of the input data.
|
17
28
|
def build(input_shape)
|
18
29
|
@input_shape = input_shape
|
19
|
-
@learning_phase = true
|
20
30
|
@built = true
|
21
31
|
end
|
22
|
-
|
23
|
-
#
|
24
|
-
# @return [Bool] If layer have already been built then return true.
|
32
|
+
|
33
|
+
# @return [Boolean] If layer have already been built then return true.
|
25
34
|
def built?
|
26
35
|
@built
|
27
36
|
end
|
28
37
|
|
29
38
|
# Forward propagation.
|
39
|
+
# @param [Numo::SFloat] x Input data.
|
30
40
|
def forward(x)
|
31
41
|
raise NotImplementedError.new("Class '#{self.class.name}' has implement method 'forward'")
|
32
42
|
end
|
33
43
|
|
34
44
|
# Backward propagation.
|
45
|
+
# @param [Numo::SFloat] dy Differential value of output data.
|
35
46
|
def backward(dy)
|
36
47
|
raise NotImplementedError.new("Class '#{self.class.name}' has implement method 'backward'")
|
37
48
|
end
|
@@ -45,73 +56,88 @@ module DNN
|
|
45
56
|
|
46
57
|
# Layer to a hash.
|
47
58
|
def to_hash(merge_hash = nil)
|
48
|
-
hash = {class: self.class.name}
|
59
|
+
hash = { class: self.class.name }
|
49
60
|
hash.merge!(merge_hash) if merge_hash
|
50
61
|
hash
|
51
62
|
end
|
52
63
|
end
|
53
|
-
|
54
|
-
|
64
|
+
|
65
|
+
|
55
66
|
# This class is a superclass of all classes with learning parameters.
|
56
67
|
class HasParamLayer < Layer
|
57
|
-
# @return [
|
68
|
+
# @return [Boolean] Setting false prevents learning of parameters.
|
58
69
|
attr_accessor :trainable
|
59
|
-
|
60
|
-
attr_reader :params
|
61
|
-
|
70
|
+
|
62
71
|
def initialize
|
63
72
|
super()
|
64
|
-
@params = {}
|
65
73
|
@trainable = true
|
66
74
|
end
|
75
|
+
|
76
|
+
# @return [Array] The parameters of the layer.
|
77
|
+
def get_params
|
78
|
+
raise NotImplementedError.new("Class '#{self.class.name}' has implement method 'get_params'")
|
79
|
+
end
|
67
80
|
end
|
68
|
-
|
69
|
-
|
81
|
+
|
82
|
+
|
70
83
|
class InputLayer < Layer
|
84
|
+
def self.call(input)
|
85
|
+
shape = input.is_a?(Array) ? input[0].shape : input.shape
|
86
|
+
self.new(shape[1..-1]).(input)
|
87
|
+
end
|
88
|
+
|
71
89
|
def self.from_hash(hash)
|
72
90
|
self.new(hash[:input_shape])
|
73
91
|
end
|
74
92
|
|
93
|
+
# @param [Array] input_dim_or_shape Setting the shape or dimension of the input data.
|
75
94
|
def initialize(input_dim_or_shape)
|
76
95
|
super()
|
77
96
|
@input_shape = input_dim_or_shape.is_a?(Array) ? input_dim_or_shape : [input_dim_or_shape]
|
78
97
|
end
|
79
98
|
|
99
|
+
def call(input)
|
100
|
+
build unless built?
|
101
|
+
x, prev_link, learning_phase = *input
|
102
|
+
link = prev_link ? Link.new(prev_link, self) : Link.new(nil, self)
|
103
|
+
[forward(x), link, learning_phase]
|
104
|
+
end
|
105
|
+
|
80
106
|
def build
|
81
107
|
@built = true
|
82
|
-
@input_shape
|
83
108
|
end
|
84
109
|
|
85
110
|
def forward(x)
|
111
|
+
unless x.shape[1..-1] == @input_shape
|
112
|
+
raise DNN_ShapeError.new("The shape of x does not match the input shape. input shape is #{@input_shape}, but x shape is #{x.shape[1..-1]}.")
|
113
|
+
end
|
86
114
|
x
|
87
115
|
end
|
88
|
-
|
116
|
+
|
89
117
|
def backward(dy)
|
90
118
|
dy
|
91
119
|
end
|
92
120
|
|
93
121
|
def to_hash
|
94
|
-
super(
|
122
|
+
super(input_shape: @input_shape)
|
95
123
|
end
|
96
124
|
end
|
97
125
|
|
98
126
|
|
99
127
|
# It is a superclass of all connection layers.
|
100
128
|
class Connection < HasParamLayer
|
101
|
-
|
129
|
+
attr_reader :weight
|
130
|
+
attr_reader :bias
|
102
131
|
attr_reader :weight_initializer
|
103
|
-
# @return [DNN::Initializers::Initializer] Bias initializer.
|
104
132
|
attr_reader :bias_initializer
|
105
|
-
# @return [DNN::Regularizers::Regularizer] Weight regularization.
|
106
133
|
attr_reader :weight_regularizer
|
107
|
-
# @return [DNN::Regularizers::Regularizer] Bias regularization.
|
108
134
|
attr_reader :bias_regularizer
|
109
135
|
|
110
136
|
# @param [DNN::Initializers::Initializer] weight_initializer Weight initializer.
|
111
137
|
# @param [DNN::Initializers::Initializer] bias_initializer Bias initializer.
|
112
|
-
# @param [DNN::Regularizers::Regularizer] weight_regularizer Weight
|
113
|
-
# @param [DNN::Regularizers::Regularizer] bias_regularizer Bias
|
114
|
-
# @param [
|
138
|
+
# @param [DNN::Regularizers::Regularizer | NilClass] weight_regularizer Weight regularizer.
|
139
|
+
# @param [DNN::Regularizers::Regularizer | NilClass] bias_regularizer Bias regularizer.
|
140
|
+
# @param [Boolean] use_bias Whether to use bias.
|
115
141
|
def initialize(weight_initializer: Initializers::RandomNormal.new,
|
116
142
|
bias_initializer: Initializers::Zeros.new,
|
117
143
|
weight_regularizer: nil,
|
@@ -122,12 +148,8 @@ module DNN
|
|
122
148
|
@bias_initializer = bias_initializer
|
123
149
|
@weight_regularizer = weight_regularizer
|
124
150
|
@bias_regularizer = bias_regularizer
|
125
|
-
@
|
126
|
-
|
127
|
-
@params[:bias] = @bias = Param.new(nil, 0)
|
128
|
-
else
|
129
|
-
@bias = nil
|
130
|
-
end
|
151
|
+
@weight = Param.new(nil, 0)
|
152
|
+
@bias = use_bias ? Param.new(nil, 0) : nil
|
131
153
|
end
|
132
154
|
|
133
155
|
def regularizers
|
@@ -137,17 +159,21 @@ module DNN
|
|
137
159
|
regularizers
|
138
160
|
end
|
139
161
|
|
140
|
-
# @return [
|
162
|
+
# @return [Boolean] Return whether to use bias.
|
141
163
|
def use_bias
|
142
164
|
@bias ? true : false
|
143
165
|
end
|
144
166
|
|
145
167
|
def to_hash(merge_hash)
|
146
|
-
super({weight_initializer: @weight_initializer.to_hash,
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
168
|
+
super({ weight_initializer: @weight_initializer.to_hash,
|
169
|
+
bias_initializer: @bias_initializer.to_hash,
|
170
|
+
weight_regularizer: @weight_regularizer&.to_hash,
|
171
|
+
bias_regularizer: @bias_regularizer&.to_hash,
|
172
|
+
use_bias: use_bias }.merge(merge_hash))
|
173
|
+
end
|
174
|
+
|
175
|
+
def get_params
|
176
|
+
{ weight: @weight, bias: @bias }
|
151
177
|
end
|
152
178
|
|
153
179
|
private def init_weight_and_bias
|
@@ -159,23 +185,21 @@ module DNN
|
|
159
185
|
end
|
160
186
|
end
|
161
187
|
end
|
162
|
-
|
163
|
-
|
164
|
-
# Full connnection layer.
|
188
|
+
|
189
|
+
|
165
190
|
class Dense < Connection
|
166
|
-
# @return [Integer] number of nodes.
|
167
191
|
attr_reader :num_nodes
|
168
192
|
|
169
193
|
def self.from_hash(hash)
|
170
194
|
self.new(hash[:num_nodes],
|
171
|
-
weight_initializer: Utils.
|
172
|
-
bias_initializer: Utils.
|
173
|
-
weight_regularizer: Utils.
|
174
|
-
bias_regularizer: Utils.
|
195
|
+
weight_initializer: Utils.hash_to_obj(hash[:weight_initializer]),
|
196
|
+
bias_initializer: Utils.hash_to_obj(hash[:bias_initializer]),
|
197
|
+
weight_regularizer: Utils.hash_to_obj(hash[:weight_regularizer]),
|
198
|
+
bias_regularizer: Utils.hash_to_obj(hash[:bias_regularizer]),
|
175
199
|
use_bias: hash[:use_bias])
|
176
200
|
end
|
177
201
|
|
178
|
-
# @param [Integer] num_nodes
|
202
|
+
# @param [Integer] num_nodes Number of nodes.
|
179
203
|
def initialize(num_nodes,
|
180
204
|
weight_initializer: Initializers::RandomNormal.new,
|
181
205
|
bias_initializer: Initializers::Zeros.new,
|
@@ -204,7 +228,7 @@ module DNN
|
|
204
228
|
y += @bias.data if @bias
|
205
229
|
y
|
206
230
|
end
|
207
|
-
|
231
|
+
|
208
232
|
def backward(dy)
|
209
233
|
if @trainable
|
210
234
|
@weight.grad += @x.transpose.dot(dy)
|
@@ -212,22 +236,22 @@ module DNN
|
|
212
236
|
end
|
213
237
|
dy.dot(@weight.data.transpose)
|
214
238
|
end
|
215
|
-
|
239
|
+
|
216
240
|
def output_shape
|
217
241
|
[@num_nodes]
|
218
242
|
end
|
219
243
|
|
220
244
|
def to_hash
|
221
|
-
super(
|
245
|
+
super(num_nodes: @num_nodes)
|
222
246
|
end
|
223
247
|
end
|
224
|
-
|
248
|
+
|
225
249
|
|
226
250
|
class Flatten < Layer
|
227
251
|
def forward(x)
|
228
252
|
x.reshape(x.shape[0], *output_shape)
|
229
253
|
end
|
230
|
-
|
254
|
+
|
231
255
|
def backward(dy)
|
232
256
|
dy.reshape(dy.shape[0], *@input_shape)
|
233
257
|
end
|
@@ -261,50 +285,59 @@ module DNN
|
|
261
285
|
end
|
262
286
|
|
263
287
|
def to_hash
|
264
|
-
super(
|
288
|
+
super(output_shape: @output_shape)
|
265
289
|
end
|
266
290
|
end
|
267
291
|
|
268
|
-
|
292
|
+
|
269
293
|
class Dropout < Layer
|
270
|
-
# @return [Float] dropout ratio.
|
271
294
|
attr_accessor :dropout_ratio
|
272
|
-
# @return [Float] Use 'weight scaling inference rule'.
|
273
295
|
attr_reader :use_scale
|
274
296
|
|
275
297
|
def self.from_hash(hash)
|
276
298
|
self.new(hash[:dropout_ratio], seed: hash[:seed], use_scale: hash[:use_scale])
|
277
299
|
end
|
278
300
|
|
301
|
+
# @param [Float] dropout_ratio Nodes dropout ratio.
|
302
|
+
# @param [Integer] seed Seed of random number used for masking.
|
303
|
+
# @param [Boolean] use_scale Set to true to scale the output according to the dropout ratio.
|
279
304
|
def initialize(dropout_ratio = 0.5, seed: rand(1 << 31), use_scale: true)
|
280
305
|
super()
|
281
306
|
@dropout_ratio = dropout_ratio
|
282
307
|
@seed = seed
|
283
308
|
@use_scale = use_scale
|
284
309
|
@mask = nil
|
310
|
+
@rnd = Random.new(@seed)
|
285
311
|
end
|
286
312
|
|
287
|
-
def
|
313
|
+
def call(input)
|
314
|
+
x, prev_link, learning_phase = *input
|
315
|
+
build(x.shape[1..-1]) unless built?
|
316
|
+
y = forward(x, learning_phase)
|
317
|
+
link = Link.new(prev_link, self)
|
318
|
+
[y, link, learning_phase]
|
319
|
+
end
|
320
|
+
|
321
|
+
def forward(x, learning_phase)
|
288
322
|
if learning_phase
|
289
|
-
Xumo::SFloat.srand(@
|
323
|
+
Xumo::SFloat.srand(@rnd.rand(1 << 31))
|
290
324
|
@mask = Xumo::SFloat.ones(*x.shape).rand < @dropout_ratio
|
291
325
|
x[@mask] = 0
|
292
|
-
|
293
|
-
x *= (1 - @dropout_ratio)
|
326
|
+
elsif @use_scale
|
327
|
+
x *= (1 - @dropout_ratio)
|
294
328
|
end
|
295
329
|
x
|
296
330
|
end
|
297
|
-
|
331
|
+
|
298
332
|
def backward(dy)
|
299
333
|
dy[@mask] = 0
|
300
334
|
dy
|
301
335
|
end
|
302
336
|
|
303
337
|
def to_hash
|
304
|
-
super(
|
338
|
+
super(dropout_ratio: @dropout_ratio, seed: @seed, use_scale: @use_scale)
|
305
339
|
end
|
306
340
|
end
|
307
|
-
|
341
|
+
|
308
342
|
end
|
309
|
-
|
310
343
|
end
|