ruby-dnn 0.9.4 → 0.10.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 +39 -3
- data/Rakefile +6 -0
- data/examples/cifar100_example.rb +71 -0
- data/examples/cifar10_example.rb +2 -1
- data/examples/iris_example.rb +2 -1
- data/examples/mnist_conv2d_example.rb +2 -1
- data/examples/mnist_example.rb +2 -3
- data/examples/mnist_lstm_example.rb +2 -1
- data/ext/cifar_loader/cifar_loader.c +77 -0
- data/ext/cifar_loader/extconf.rb +3 -0
- data/lib/dnn.rb +1 -0
- data/lib/dnn/{lib/cifar10.rb → cifar10.rb} +9 -11
- data/lib/dnn/cifar100.rb +49 -0
- data/lib/dnn/core/activations.rb +28 -24
- data/lib/dnn/core/cnn_layers.rb +216 -94
- data/lib/dnn/core/dataset.rb +21 -5
- data/lib/dnn/core/initializers.rb +3 -3
- data/lib/dnn/core/layers.rb +81 -150
- data/lib/dnn/core/losses.rb +88 -49
- data/lib/dnn/core/model.rb +97 -74
- data/lib/dnn/core/normalizations.rb +72 -0
- data/lib/dnn/core/optimizers.rb +171 -78
- data/lib/dnn/core/regularizers.rb +92 -22
- data/lib/dnn/core/rnn_layers.rb +146 -121
- data/lib/dnn/core/utils.rb +4 -3
- data/lib/dnn/{lib/downloader.rb → downloader.rb} +5 -1
- data/lib/dnn/{lib/image.rb → image.rb} +1 -1
- data/lib/dnn/{lib/iris.rb → iris.rb} +1 -1
- data/lib/dnn/{lib/mnist.rb → mnist.rb} +4 -3
- data/lib/dnn/version.rb +1 -1
- data/ruby-dnn.gemspec +1 -1
- metadata +13 -12
- data/API-Reference.ja.md +0 -978
- data/LIB-API-Reference.ja.md +0 -97
- data/ext/cifar10_loader/cifar10_loader.c +0 -44
- data/ext/cifar10_loader/extconf.rb +0 -3
data/lib/dnn/core/cnn_layers.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module DNN
|
2
2
|
module Layers
|
3
3
|
# This module is used for convolution.
|
4
|
-
module
|
4
|
+
module Conv2D_Utils
|
5
5
|
private
|
6
6
|
|
7
7
|
# img[bsize, out_h, out_w, ch] to col[bsize * out_h * out_w, fil_h * fil_w * ch]
|
@@ -34,7 +34,7 @@ module DNN
|
|
34
34
|
img
|
35
35
|
end
|
36
36
|
|
37
|
-
def
|
37
|
+
def zero_padding(img, pad)
|
38
38
|
bsize, img_h, img_w, ch = img.shape
|
39
39
|
img2 = Xumo::SFloat.zeros(bsize, img_h + pad[0], img_w + pad[1], ch)
|
40
40
|
i_begin = pad[0] / 2
|
@@ -45,7 +45,7 @@ module DNN
|
|
45
45
|
img2
|
46
46
|
end
|
47
47
|
|
48
|
-
def
|
48
|
+
def zero_padding_bwd(img, pad)
|
49
49
|
i_begin = pad[0] / 2
|
50
50
|
i_end = img.shape[1] - (pad[0] / 2.0).round
|
51
51
|
j_begin = pad[1] / 2
|
@@ -53,22 +53,34 @@ module DNN
|
|
53
53
|
img[true, i_begin...i_end, j_begin...j_end, true]
|
54
54
|
end
|
55
55
|
|
56
|
-
def
|
57
|
-
out_h = (prev_h - fil_h) / strides[0] + 1
|
58
|
-
out_w = (prev_w - fil_w) / strides[1] + 1
|
56
|
+
def calc_conv2d_out_size(prev_h, prev_w, fil_h, fil_w, pad_h, pad_w, strides)
|
57
|
+
out_h = (prev_h + pad_h - fil_h) / strides[0] + 1
|
58
|
+
out_w = (prev_w + pad_w - fil_w) / strides[1] + 1
|
59
59
|
[out_h, out_w]
|
60
60
|
end
|
61
61
|
|
62
|
-
def
|
62
|
+
def calc_deconv2d_out_size(prev_h, prev_w, fil_h, fil_w, pad_h, pad_w, strides)
|
63
|
+
out_h = (prev_h - 1) * strides[0] + fil_h - pad_h
|
64
|
+
out_w = (prev_w - 1) * strides[1] + fil_w - pad_w
|
65
|
+
[out_h, out_w]
|
66
|
+
end
|
67
|
+
|
68
|
+
def calc_padding_size(prev_h, prev_w, out_h, out_w, strides)
|
63
69
|
pad_h = (prev_h.to_f / strides[0]).ceil - out_h
|
64
70
|
pad_w = (prev_w.to_f / strides[1]).ceil - out_w
|
65
71
|
[pad_h, pad_w]
|
66
72
|
end
|
73
|
+
|
74
|
+
def calc_padding_size(prev_h, prev_w, out_h, out_w, strides)
|
75
|
+
pad_h = ((prev_h.to_f / strides[0]).ceil - out_h) * strides[0]
|
76
|
+
pad_w = ((prev_w.to_f / strides[1]).ceil - out_w) * strides[1]
|
77
|
+
[pad_h, pad_w]
|
78
|
+
end
|
67
79
|
end
|
68
80
|
|
69
81
|
|
70
82
|
class Conv2D < Connection
|
71
|
-
include
|
83
|
+
include Conv2D_Utils
|
72
84
|
|
73
85
|
# @return [Integer] number of filters.
|
74
86
|
attr_reader :num_filters
|
@@ -76,75 +88,81 @@ module DNN
|
|
76
88
|
attr_reader :filter_size
|
77
89
|
# @return [Array] Return stride length. stride length is of the form [height, width].
|
78
90
|
attr_reader :strides
|
91
|
+
# @return [Array | Bool] Return padding size or whether to padding.
|
92
|
+
attr_reader :padding
|
79
93
|
|
80
|
-
def self.
|
94
|
+
def self.from_hash(hash)
|
81
95
|
Conv2D.new(hash[:num_filters], hash[:filter_size],
|
82
|
-
weight_initializer: Utils.
|
83
|
-
bias_initializer: Utils.
|
96
|
+
weight_initializer: Utils.from_hash(hash[:weight_initializer]),
|
97
|
+
bias_initializer: Utils.from_hash(hash[:bias_initializer]),
|
98
|
+
weight_regularizer: Utils.from_hash(hash[:weight_regularizer]),
|
99
|
+
bias_regularizer: Utils.from_hash(hash[:bias_regularizer]),
|
100
|
+
use_bias: hash[:use_bias],
|
84
101
|
strides: hash[:strides],
|
85
|
-
padding: hash[:padding]
|
86
|
-
l1_lambda: hash[:l1_lambda],
|
87
|
-
l2_lambda: hash[:l2_lambda],
|
88
|
-
use_bias: hash[:use_bias])
|
102
|
+
padding: hash[:padding])
|
89
103
|
end
|
90
104
|
|
91
|
-
# @param [Integer] num_filters
|
92
|
-
# @param [Array
|
93
|
-
# @param [Array
|
94
|
-
# @param [Bool] padding
|
105
|
+
# @param [Integer] num_filters Number of filters.
|
106
|
+
# @param [Array | Integer] filter_size Filter size. Filter size is of the form [height, width].
|
107
|
+
# @param [Array | Integer] strides Stride length. Stride length is of the form [height, width].
|
108
|
+
# @param [Array | Bool] padding Padding size or whether to padding. Padding size is of the form [height, width].
|
95
109
|
def initialize(num_filters, filter_size,
|
96
110
|
weight_initializer: Initializers::RandomNormal.new,
|
97
111
|
bias_initializer: Initializers::Zeros.new,
|
112
|
+
weight_regularizer: nil,
|
113
|
+
bias_regularizer: nil,
|
114
|
+
use_bias: true,
|
98
115
|
strides: 1,
|
99
|
-
padding: false
|
100
|
-
l1_lambda: 0,
|
101
|
-
l2_lambda: 0,
|
102
|
-
use_bias: true)
|
116
|
+
padding: false)
|
103
117
|
super(weight_initializer: weight_initializer, bias_initializer: bias_initializer,
|
104
|
-
|
118
|
+
weight_regularizer: weight_regularizer, bias_regularizer: bias_regularizer, use_bias: use_bias)
|
105
119
|
@num_filters = num_filters
|
106
120
|
@filter_size = filter_size.is_a?(Integer) ? [filter_size, filter_size] : filter_size
|
107
121
|
@strides = strides.is_a?(Integer) ? [strides, strides] : strides
|
108
|
-
@padding = padding
|
122
|
+
@padding = padding.is_a?(Integer) ? [padding, padding] : padding
|
109
123
|
end
|
110
124
|
|
111
125
|
def build(input_shape)
|
112
126
|
super
|
113
|
-
prev_h, prev_w = input_shape
|
114
|
-
@
|
115
|
-
if @
|
116
|
-
|
117
|
-
|
127
|
+
prev_h, prev_w, num_prev_filter = *input_shape
|
128
|
+
@weight.data = Xumo::SFloat.new(@filter_size.reduce(:*) * num_prev_filter, @num_filters)
|
129
|
+
@bias.data = Xumo::SFloat.new(@num_filters) if @bias
|
130
|
+
init_weight_and_bias
|
131
|
+
if @padding == true
|
132
|
+
out_h, out_w = calc_conv2d_out_size(prev_h, prev_w, *@filter_size, 0, 0, @strides)
|
133
|
+
@pad_size = calc_padding_size(prev_h, prev_w, out_h, out_w, @strides)
|
134
|
+
elsif @padding.is_a?(Array)
|
135
|
+
@pad_size = @padding
|
136
|
+
else
|
137
|
+
@pad_size = [0, 0]
|
118
138
|
end
|
139
|
+
@out_size = calc_conv2d_out_size(prev_h, prev_w, *@filter_size, *@pad_size, @strides)
|
119
140
|
end
|
120
141
|
|
121
142
|
def forward(x)
|
122
|
-
x =
|
143
|
+
x = zero_padding(x, @pad_size) if @padding
|
123
144
|
@x_shape = x.shape
|
124
145
|
@col = im2col(x, *@out_size, *@filter_size, @strides)
|
125
|
-
|
126
|
-
|
127
|
-
|
146
|
+
y = @col.dot(@weight.data)
|
147
|
+
y += @bias.data if @bias
|
148
|
+
y.reshape(x.shape[0], *@out_size, y.shape[3])
|
128
149
|
end
|
129
150
|
|
130
|
-
def backward(
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
151
|
+
def backward(dy)
|
152
|
+
dy = dy.reshape(dy.shape[0..2].reduce(:*), dy.shape[3])
|
153
|
+
if @trainable
|
154
|
+
@weight.grad += @col.transpose.dot(dy)
|
155
|
+
@bias.grad += dy.sum(0) if @bias
|
156
|
+
end
|
157
|
+
dcol = dy.dot(@weight.data.transpose)
|
135
158
|
dx = col2im(dcol, @x_shape, *@out_size, *@filter_size, @strides)
|
136
|
-
@padding ?
|
159
|
+
@padding ? zero_padding_bwd(dx, @pad_size) : dx
|
137
160
|
end
|
138
161
|
|
139
162
|
def output_shape
|
140
163
|
[*@out_size, @num_filters]
|
141
164
|
end
|
142
165
|
|
143
|
-
# @return [Bool] whether to padding.
|
144
|
-
def padding?
|
145
|
-
@padding
|
146
|
-
end
|
147
|
-
|
148
166
|
# @return [Numo::SFloat] Convert weight to filter and return.
|
149
167
|
def filters
|
150
168
|
num_prev_filter = @input_shape[2]
|
@@ -163,35 +181,140 @@ module DNN
|
|
163
181
|
strides: @strides,
|
164
182
|
padding: @padding})
|
165
183
|
end
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
class Conv2D_Transpose < Connection
|
188
|
+
include Conv2D_Utils
|
189
|
+
|
190
|
+
# @return [Integer] number of filters.
|
191
|
+
attr_reader :num_filters
|
192
|
+
# @return [Array] Return filter size. filter size is of the form [height, width].
|
193
|
+
attr_reader :filter_size
|
194
|
+
# @return [Array] Return stride length. stride length is of the form [height, width].
|
195
|
+
attr_reader :strides
|
196
|
+
# @return [Array] Return padding size.
|
197
|
+
attr_reader :padding
|
198
|
+
|
199
|
+
def self.from_hash(hash)
|
200
|
+
Conv2D_Transpose.new(hash[:num_filters], hash[:filter_size],
|
201
|
+
weight_initializer: Utils.from_hash(hash[:weight_initializer]),
|
202
|
+
bias_initializer: Utils.from_hash(hash[:bias_initializer]),
|
203
|
+
weight_regularizer: Utils.from_hash(hash[:weight_regularizer]),
|
204
|
+
bias_regularizer: Utils.from_hash(hash[:bias_regularizer]),
|
205
|
+
use_bias: hash[:use_bias],
|
206
|
+
strides: hash[:strides],
|
207
|
+
padding: hash[:padding])
|
208
|
+
end
|
209
|
+
|
210
|
+
# @param [Integer] num_filters Number of filters.
|
211
|
+
# @param [Array | Integer] filter_size Filter size. Filter size is of the form [height, width].
|
212
|
+
# @param [Array | Integer] strides Stride length. Stride length is of the form [height, width].
|
213
|
+
# @param [Array] padding Padding size. Padding size is of the form [height, width].
|
214
|
+
def initialize(num_filters, filter_size,
|
215
|
+
weight_initializer: Initializers::RandomNormal.new,
|
216
|
+
bias_initializer: Initializers::Zeros.new,
|
217
|
+
weight_regularizer: nil,
|
218
|
+
bias_regularizer: nil,
|
219
|
+
use_bias: true,
|
220
|
+
strides: 1,
|
221
|
+
padding: false)
|
222
|
+
super(weight_initializer: weight_initializer, bias_initializer: bias_initializer,
|
223
|
+
weight_regularizer: weight_regularizer, bias_regularizer: bias_regularizer, use_bias: use_bias)
|
224
|
+
@num_filters = num_filters
|
225
|
+
@filter_size = filter_size.is_a?(Integer) ? [filter_size, filter_size] : filter_size
|
226
|
+
@strides = strides.is_a?(Integer) ? [strides, strides] : strides
|
227
|
+
@padding = padding.is_a?(Integer) ? [padding, padding] : padding
|
228
|
+
end
|
229
|
+
|
230
|
+
def build(input_shape)
|
231
|
+
super
|
232
|
+
prev_h, prev_w, num_prev_filter = *input_shape
|
233
|
+
@weight.data = Xumo::SFloat.new(@filter_size.reduce(:*) * @num_filters, num_prev_filter)
|
234
|
+
@weight_initializer.init_param(self, @weight)
|
235
|
+
@weight_regularizer.param = @weight if @weight_regularizer
|
236
|
+
if @bias
|
237
|
+
@bias.data = Xumo::SFloat.new(@num_filters)
|
238
|
+
@bias_initializer.init_param(self, @bias)
|
239
|
+
@bias_regularizer.param = @bias if @bias_regularizer
|
240
|
+
end
|
241
|
+
if @padding == true
|
242
|
+
out_h, out_w = calc_deconv2d_out_size(prev_h, prev_w, *@filter_size, 0, 0, @strides)
|
243
|
+
@pad_size = calc_padding_size(out_h, out_w, prev_h, prev_w, @strides)
|
244
|
+
elsif @padding.is_a?(Array)
|
245
|
+
@pad_size = @padding
|
246
|
+
else
|
247
|
+
@pad_size = [0, 0]
|
248
|
+
end
|
249
|
+
@out_size = calc_deconv2d_out_size(prev_h, prev_w, *@filter_size, *@pad_size, @strides)
|
250
|
+
end
|
251
|
+
|
252
|
+
def forward(x)
|
253
|
+
bsize = x.shape[0]
|
254
|
+
x = x.reshape(x.shape[0..2].reduce(:*), x.shape[3])
|
255
|
+
@x = x
|
256
|
+
col = x.dot(@weight.data.transpose)
|
257
|
+
img_shape = [bsize, @out_size[0] + @pad_size[0], @out_size[1] + @pad_size[1], @num_filters]
|
258
|
+
y = col2im(col, img_shape, *input_shape[0..1], *@filter_size, @strides)
|
259
|
+
y += @bias.data if @bias
|
260
|
+
@padding ? zero_padding_bwd(y, @pad_size) : y
|
261
|
+
end
|
262
|
+
|
263
|
+
def backward(dy)
|
264
|
+
dy = zero_padding(dy, @pad_size) if @padding
|
265
|
+
col = im2col(dy, *input_shape[0..1], *@filter_size, @strides)
|
266
|
+
if @trainable
|
267
|
+
@weight.grad += col.transpose.dot(@x)
|
268
|
+
@bias.grad += col.reshape(col.shape[0] * @filter_size.reduce(:*), @num_filters).sum(0) if @bias
|
269
|
+
end
|
270
|
+
dx = col.dot(@weight.data)
|
271
|
+
dx.reshape(dy.shape[0], *input_shape)
|
272
|
+
end
|
273
|
+
|
274
|
+
def output_shape
|
275
|
+
[*@out_size, @num_filters]
|
276
|
+
end
|
277
|
+
|
278
|
+
# @return [Numo::SFloat] Convert weight to filter and return.
|
279
|
+
def filters
|
170
280
|
num_prev_filter = @input_shape[2]
|
171
|
-
@weight.data
|
172
|
-
|
173
|
-
|
281
|
+
@weight.data.reshape(*@filter_size, @num_filters, num_prev_filter)
|
282
|
+
end
|
283
|
+
|
284
|
+
# @param [Numo::SFloat] filters Convert weight to filters and set.
|
285
|
+
def filters=(filters)
|
286
|
+
num_prev_filter = @input_shape[2]
|
287
|
+
@weight.data = filters.reshape(@filter_size.reduce(:*) * @num_filters, num_prev_filter)
|
288
|
+
end
|
289
|
+
|
290
|
+
def to_hash
|
291
|
+
super({num_filters: @num_filters,
|
292
|
+
filter_size: @filter_size,
|
293
|
+
strides: @strides,
|
294
|
+
padding: @padding})
|
174
295
|
end
|
175
296
|
end
|
176
297
|
|
177
298
|
|
178
299
|
# Super class of all pooling2D class.
|
179
300
|
class Pool2D < Layer
|
180
|
-
include
|
301
|
+
include Conv2D_Utils
|
181
302
|
|
182
|
-
# @return [Array] Return pooling size.
|
303
|
+
# @return [Array] Return pooling size. Pooling size is of the form [height, width].
|
183
304
|
attr_reader :pool_size
|
184
|
-
# @return [Array] Return stride length.
|
305
|
+
# @return [Array] Return stride length. Stride length is of the form [height, width].
|
185
306
|
attr_reader :strides
|
307
|
+
# @return [Array | Bool] Return padding size or whether to padding.
|
308
|
+
attr_reader :padding
|
186
309
|
|
187
|
-
def self.
|
310
|
+
def self.from_hash(pool2d_class, hash)
|
188
311
|
pool2d_class.new(hash[:pool_size], strides: hash[:strides], padding: hash[:padding])
|
189
312
|
end
|
190
313
|
|
191
|
-
# @param [Array
|
192
|
-
# @param [Array
|
314
|
+
# @param [Array | Integer] pool_size Pooling size. Pooling size is of the form [height, width].
|
315
|
+
# @param [Array | Integer | NilClass] strides stride length. Stride length is of the form [height, width].
|
193
316
|
# If you set nil, treat pool_size as strides.
|
194
|
-
# @param [Bool] padding
|
317
|
+
# @param [Array | Bool] padding Padding size or whether to padding. Padding size is of the form [height, width].
|
195
318
|
def initialize(pool_size, strides: nil, padding: false)
|
196
319
|
super()
|
197
320
|
@pool_size = pool_size.is_a?(Integer) ? [pool_size, pool_size] : pool_size
|
@@ -200,29 +323,28 @@ module DNN
|
|
200
323
|
else
|
201
324
|
@pool_size.clone
|
202
325
|
end
|
203
|
-
@padding = padding
|
326
|
+
@padding = padding.is_a?(Integer) ? [padding, padding] : padding
|
204
327
|
end
|
205
328
|
|
206
329
|
def build(input_shape)
|
207
330
|
super
|
208
331
|
prev_h, prev_w = input_shape[0..1]
|
209
332
|
@num_channel = input_shape[2]
|
210
|
-
@
|
211
|
-
|
212
|
-
@pad_size =
|
213
|
-
|
333
|
+
if @padding == true
|
334
|
+
out_h, out_w = calc_conv2d_out_size(prev_h, prev_w, *@pool_size, 0, 0, @strides)
|
335
|
+
@pad_size = calc_padding_size(prev_h, prev_w, out_h, out_w, @strides)
|
336
|
+
elsif @padding.is_a?(Array)
|
337
|
+
@pad_size = @padding
|
338
|
+
else
|
339
|
+
@pad_size = [0, 0]
|
214
340
|
end
|
341
|
+
@out_size = calc_conv2d_out_size(prev_h, prev_w, *@pool_size, *@pad_size, @strides)
|
215
342
|
end
|
216
343
|
|
217
344
|
def output_shape
|
218
345
|
[*@out_size, @num_channel]
|
219
346
|
end
|
220
347
|
|
221
|
-
# @return [Bool] whether to padding.
|
222
|
-
def padding?
|
223
|
-
@padding
|
224
|
-
end
|
225
|
-
|
226
348
|
def to_hash
|
227
349
|
super({pool_size: @pool_size,
|
228
350
|
strides: @strides,
|
@@ -232,12 +354,12 @@ module DNN
|
|
232
354
|
|
233
355
|
|
234
356
|
class MaxPool2D < Pool2D
|
235
|
-
def self.
|
236
|
-
Pool2D.
|
357
|
+
def self.from_hash(hash)
|
358
|
+
Pool2D.from_hash(self, hash)
|
237
359
|
end
|
238
360
|
|
239
361
|
def forward(x)
|
240
|
-
x =
|
362
|
+
x = zero_padding(x, @pad_size) if @padding
|
241
363
|
@x_shape = x.shape
|
242
364
|
col = im2col(x, *@out_size, *@pool_size, @strides)
|
243
365
|
col = col.reshape(x.shape[0] * @out_size.reduce(:*), @pool_size.reduce(:*), x.shape[3]).transpose(0, 2, 1)
|
@@ -246,23 +368,23 @@ module DNN
|
|
246
368
|
col.max(1).reshape(x.shape[0], *@out_size, x.shape[3])
|
247
369
|
end
|
248
370
|
|
249
|
-
def backward(
|
250
|
-
dmax = Xumo::SFloat.zeros(
|
251
|
-
dmax[@max_index] =
|
252
|
-
dcol = dmax.reshape(
|
371
|
+
def backward(dy)
|
372
|
+
dmax = Xumo::SFloat.zeros(dy.size * @pool_size.reduce(:*))
|
373
|
+
dmax[@max_index] = dy.flatten
|
374
|
+
dcol = dmax.reshape(dy.shape[0..2].reduce(:*), @pool_size.reduce(:*) * dy.shape[3])
|
253
375
|
dx = col2im(dcol, @x_shape, *@out_size, *@pool_size, @strides)
|
254
|
-
@padding ?
|
376
|
+
@padding ? zero_padding_bwd(dx, @pad_size) : dx
|
255
377
|
end
|
256
378
|
end
|
257
379
|
|
258
380
|
|
259
381
|
class AvgPool2D < Pool2D
|
260
|
-
def self.
|
261
|
-
Pool2D.
|
382
|
+
def self.from_hash(hash)
|
383
|
+
Pool2D.from_hash(self, hash)
|
262
384
|
end
|
263
385
|
|
264
386
|
def forward(x)
|
265
|
-
x =
|
387
|
+
x = zero_padding(x, @pad_size) if @padding
|
266
388
|
@x_shape = x.shape
|
267
389
|
col = im2col(x, *@out_size, *@pool_size, @strides)
|
268
390
|
col = col.reshape(x.shape[0] * @out_size.reduce(:*), @pool_size.reduce(:*), x.shape[3]).transpose(0, 2, 1)
|
@@ -270,21 +392,23 @@ module DNN
|
|
270
392
|
col.mean(1).reshape(x.shape[0], *@out_size, x.shape[3])
|
271
393
|
end
|
272
394
|
|
273
|
-
def backward(
|
395
|
+
def backward(dy)
|
274
396
|
row_length = @pool_size.reduce(:*)
|
275
|
-
|
276
|
-
davg = Xumo::SFloat.zeros(
|
397
|
+
dy /= row_length
|
398
|
+
davg = Xumo::SFloat.zeros(dy.size, row_length)
|
277
399
|
row_length.times do |i|
|
278
|
-
davg[true, i] =
|
400
|
+
davg[true, i] = dy.flatten
|
279
401
|
end
|
280
|
-
dcol = davg.reshape(
|
402
|
+
dcol = davg.reshape(dy.shape[0..2].reduce(:*), dy.shape[3] * @pool_size.reduce(:*))
|
281
403
|
dx = col2im(dcol, @x_shape, *@out_size, *@pool_size, @strides)
|
282
|
-
@padding ?
|
404
|
+
@padding ? zero_padding_bwd(dx, @pad_size) : dx
|
283
405
|
end
|
284
406
|
end
|
285
407
|
|
286
408
|
|
287
409
|
class UnPool2D < Layer
|
410
|
+
include Conv2D_Utils
|
411
|
+
|
288
412
|
# @return [Array] Return unpooling size. unpooling size is of the form [height, width].
|
289
413
|
attr_reader :unpool_size
|
290
414
|
|
@@ -294,7 +418,7 @@ module DNN
|
|
294
418
|
@unpool_size = unpool_size.is_a?(Integer) ? [unpool_size, unpool_size] : unpool_size
|
295
419
|
end
|
296
420
|
|
297
|
-
def self.
|
421
|
+
def self.from_hash(hash)
|
298
422
|
UnPool2D.new(hash[:unpool_size])
|
299
423
|
end
|
300
424
|
|
@@ -308,8 +432,6 @@ module DNN
|
|
308
432
|
@num_channel = input_shape[2]
|
309
433
|
end
|
310
434
|
|
311
|
-
include Conv2DModule
|
312
|
-
|
313
435
|
def forward(x)
|
314
436
|
@x_shape = x.shape
|
315
437
|
unpool_h, unpool_w = @unpool_size
|
@@ -322,12 +444,12 @@ module DNN
|
|
322
444
|
x2.reshape(x.shape[0], *@out_size, x.shape[3])
|
323
445
|
end
|
324
446
|
|
325
|
-
def backward(
|
447
|
+
def backward(dy)
|
326
448
|
in_size = input_shape[0..1]
|
327
|
-
col = im2col(
|
328
|
-
col = col.reshape(
|
329
|
-
.reshape(
|
330
|
-
col.sum(1).reshape(
|
449
|
+
col = im2col(dy, *input_shape[0..1], *@unpool_size, @unpool_size)
|
450
|
+
col = col.reshape(dy.shape[0] * in_size.reduce(:*), @unpool_size.reduce(:*), dy.shape[3]).transpose(0, 2, 1)
|
451
|
+
.reshape(dy.shape[0] * in_size.reduce(:*) * dy.shape[3], @unpool_size.reduce(:*))
|
452
|
+
col.sum(1).reshape(dy.shape[0], *in_size, dy.shape[3])
|
331
453
|
end
|
332
454
|
|
333
455
|
def output_shape
|