ruby-dnn 0.9.3 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2926b7a9ca6f3766ee46bba676837bd4cb98d55220ba37e4ef12109ef244a444
4
- data.tar.gz: 57db99b2200d3d0946c6bb886f97308f6b09e550f5ab66802f61a7d13bd9b8fe
3
+ metadata.gz: 670d2d681e3929d20c5c855c97dbad1759560eb45018d20a9089c6bc62787833
4
+ data.tar.gz: a9360305a97aed1bac5300010fbfa3ea85565eab70d299a9d07acd78d6b24d63
5
5
  SHA512:
6
- metadata.gz: 19c77e661bb6b208c279ce80d85a115572e124bad50dd97f3c8ec1097aa1bf4f245cef11bee58c3ffbc5c8c3a47f4aa6e9e3bb89db0ba8c1c7ff6ef2066764b3
7
- data.tar.gz: 9a8d414fcb3401b883bde2cd54f6b320817ee66389e43971f62a4d9f85e1888db36842d704c3c2392f27f68266f6dcd8faf207723dfca25195651966e3713652
6
+ metadata.gz: d1f3b49241a81bf8c56b595bdaeecf097d8d3d461a02ab37860c6d2eede4a7e5cfadd0f83d2759cdbbdc7d541bbadebd11e55a80b0cfce9c2bd8a216efb2596d
7
+ data.tar.gz: e92230987d4c59cf4395ee33695fc974c65940f7df6aecfc3f89ebf65bbbeaae95433079df8855c448850923b5d230807eca2d2c135d475df6aa1aba6431988a
@@ -0,0 +1,33 @@
1
+ require "dnn"
2
+ require "dnn/lib/iris"
3
+ # require "numo/linalg/autoloader"
4
+
5
+ include DNN::Layers
6
+ include DNN::Activations
7
+ include DNN::Optimizers
8
+ include DNN::Losses
9
+ Model = DNN::Model
10
+ Iris = DNN::Iris
11
+
12
+ x, y = Iris.load(true)
13
+ x_train, y_train = x[0...100, true], y[0...100]
14
+ x_test, y_test = x[100...150, true], y[100...150]
15
+
16
+ x_train /= 255
17
+ x_test /= 255
18
+
19
+ y_train = DNN::Utils.to_categorical(y_train, 3, Numo::SFloat)
20
+ y_test = DNN::Utils.to_categorical(y_test, 3, Numo::SFloat)
21
+
22
+ model = Model.new
23
+
24
+ model << InputLayer.new(4)
25
+
26
+ model << Dense.new(64)
27
+ model << ReLU.new
28
+
29
+ model << Dense.new(3)
30
+
31
+ model.compile(Adam.new, SoftmaxCrossEntropy.new)
32
+
33
+ model.train(x_train, y_train, 1000, batch_size: 10, test: [x_test, y_test])
@@ -3,7 +3,7 @@ module DNN
3
3
 
4
4
  class Sigmoid < Layers::Layer
5
5
  def forward(x)
6
- @out = Utils.sigmoid(x)
6
+ @out = 1 / (1 + NMath.exp(-x))
7
7
  end
8
8
 
9
9
  def backward(dout)
@@ -4,7 +4,7 @@ module DNN
4
4
  module Conv2DModule
5
5
  private
6
6
 
7
- # img[bsize, out_h, out_w, channel] to col[bsize * out_h * out_w, fil_h * fil_w * ch]
7
+ # img[bsize, out_h, out_w, ch] to col[bsize * out_h * out_w, fil_h * fil_w * ch]
8
8
  def im2col(img, out_h, out_w, fil_h, fil_w, strides)
9
9
  bsize = img.shape[0]
10
10
  ch = img.shape[3]
@@ -19,7 +19,7 @@ module DNN
19
19
  col.reshape(bsize * out_h * out_w, fil_h * fil_w * ch)
20
20
  end
21
21
 
22
- # col[bsize * out_h * out_w, fil_h * fil_w * ch] to img[bsize, out_h, out_w, channel]
22
+ # col[bsize * out_h * out_w, fil_h * fil_w * ch] to img[bsize, out_h, out_w, ch]
23
23
  def col2im(col, img_shape, out_h, out_w, fil_h, fil_w, strides)
24
24
  bsize, img_h, img_w, ch = img_shape
25
25
  col = col.reshape(bsize, out_h, out_w, fil_h, fil_w, ch)
@@ -84,7 +84,8 @@ module DNN
84
84
  strides: hash[:strides],
85
85
  padding: hash[:padding],
86
86
  l1_lambda: hash[:l1_lambda],
87
- l2_lambda: hash[:l2_lambda])
87
+ l2_lambda: hash[:l2_lambda],
88
+ use_bias: hash[:use_bias])
88
89
  end
89
90
 
90
91
  # @param [Integer] num_filters number of filters.
@@ -93,13 +94,14 @@ module DNN
93
94
  # @param [Bool] padding Whether to padding.
94
95
  def initialize(num_filters, filter_size,
95
96
  weight_initializer: Initializers::RandomNormal.new,
96
- bias_initializer: Initializers::RandomNormal.new,
97
+ bias_initializer: Initializers::Zeros.new,
97
98
  strides: 1,
98
99
  padding: false,
99
100
  l1_lambda: 0,
100
- l2_lambda: 0)
101
+ l2_lambda: 0,
102
+ use_bias: true)
101
103
  super(weight_initializer: weight_initializer, bias_initializer: bias_initializer,
102
- l1_lambda: l1_lambda, l2_lambda: l2_lambda)
104
+ l1_lambda: l1_lambda, l2_lambda: l2_lambda, use_bias: use_bias)
103
105
  @num_filters = num_filters
104
106
  @filter_size = filter_size.is_a?(Integer) ? [filter_size, filter_size] : filter_size
105
107
  @strides = strides.is_a?(Integer) ? [strides, strides] : strides
@@ -120,14 +122,15 @@ module DNN
120
122
  x = padding(x, @pad_size) if @padding
121
123
  @x_shape = x.shape
122
124
  @col = im2col(x, *@out_size, *@filter_size, @strides)
123
- out = @col.dot(@weight.data) + @bias.data
125
+ out = @col.dot(@weight.data)
126
+ out += @bias.data if @bias
124
127
  out.reshape(x.shape[0], *@out_size, out.shape[3])
125
128
  end
126
129
 
127
130
  def backward(dout)
128
131
  dout = dout.reshape(dout.shape[0..2].reduce(:*), dout.shape[3])
129
132
  @weight.grad = @col.transpose.dot(dout)
130
- @bias.grad = dout.sum(0)
133
+ @bias.grad = dout.sum(0) if @bias
131
134
  dcol = dout.dot(@weight.data.transpose)
132
135
  dx = col2im(dcol, @x_shape, *@out_size, *@filter_size, @strides)
133
136
  @padding ? back_padding(dx, @pad_size) : dx
@@ -166,7 +169,7 @@ module DNN
166
169
  def init_params
167
170
  num_prev_filter = @input_shape[2]
168
171
  @weight.data = Xumo::SFloat.new(@filter_size.reduce(:*) * num_prev_filter, @num_filters)
169
- @bias.data = Xumo::SFloat.new(@num_filters)
172
+ @bias.data = Xumo::SFloat.new(@num_filters) if @bias
170
173
  super()
171
174
  end
172
175
  end
@@ -305,18 +308,26 @@ module DNN
305
308
  @num_channel = input_shape[2]
306
309
  end
307
310
 
311
+ include Conv2DModule
312
+
308
313
  def forward(x)
309
314
  @x_shape = x.shape
310
315
  unpool_h, unpool_w = @unpool_size
311
316
  x2 = Xumo::SFloat.zeros(x.shape[0], x.shape[1], unpool_h, x.shape[2], unpool_w, @num_channel)
312
- x2[true, true, 0, true, 0, true] = x
317
+ unpool_h.times do |i|
318
+ unpool_w.times do |j|
319
+ x2[true, true, i, true, j, true] = x
320
+ end
321
+ end
313
322
  x2.reshape(x.shape[0], *@out_size, x.shape[3])
314
323
  end
315
324
 
316
325
  def backward(dout)
317
- unpool_h, unpool_w = @unpool_size
318
- dout = dout.reshape(dout.shape[0], @x_shape[1], unpool_h, @x_shape[2], unpool_w, @num_channel)
319
- dout[true, true, 0, true, 0, true].clone
326
+ in_size = input_shape[0..1]
327
+ col = im2col(dout, *input_shape[0..1], *@unpool_size, @unpool_size)
328
+ col = col.reshape(dout.shape[0] * in_size.reduce(:*), @unpool_size.reduce(:*), dout.shape[3]).transpose(0, 2, 1)
329
+ .reshape(dout.shape[0] * in_size.reduce(:*) * dout.shape[3], @unpool_size.reduce(:*))
330
+ col.sum(1).reshape(dout.shape[0], *in_size, dout.shape[3])
320
331
  end
321
332
 
322
333
  def output_shape
@@ -113,26 +113,34 @@ module DNN
113
113
  attr_reader :weight_initializer
114
114
  # @return [DNN::Initializers] bias initializer.
115
115
  attr_reader :bias_initializer
116
- # @return [Float] L1 regularization
116
+ # @return [Float] L1 regularization.
117
117
  attr_reader :l1_lambda
118
- # @return [Float] L2 regularization
118
+ # @return [Float] L2 regularization.
119
119
  attr_reader :l2_lambda
120
120
 
121
121
  # @param [DNN::Initializers] weight_initializer weight initializer.
122
122
  # @param [DNN::Initializers] bias_initializer bias initializer.
123
123
  # @param [Float] l1_lambda L1 regularization
124
124
  # @param [Float] l2_lambda L2 regularization
125
+ # @param [Bool] use_bias whether to use bias.
125
126
  def initialize(weight_initializer: Initializers::RandomNormal.new,
126
127
  bias_initializer: Initializers::Zeros.new,
127
128
  l1_lambda: 0,
128
- l2_lambda: 0)
129
+ l2_lambda: 0,
130
+ use_bias: true)
129
131
  super()
130
132
  @weight_initializer = weight_initializer
131
133
  @bias_initializer = bias_initializer
132
134
  @l1_lambda = l1_lambda
133
135
  @l2_lambda = l2_lambda
134
136
  @params[:weight] = @weight = Param.new
135
- @params[:bias] = @bias = Param.new
137
+ # For compatibility on or before with v0.9.3, setting use_bias to nil use bias.
138
+ # Therefore, setting use_bias to nil is deprecated.
139
+ if use_bias || use_bias == nil
140
+ @params[:bias] = @bias = Param.new
141
+ else
142
+ @params[:bias] = @bias = nil
143
+ end
136
144
  end
137
145
 
138
146
  def regularizers
@@ -142,6 +150,11 @@ module DNN
142
150
  regularizers
143
151
  end
144
152
 
153
+ # @return [Bool] Return whether to use bias.
154
+ def use_bias
155
+ @bias ? true : false
156
+ end
157
+
145
158
  def to_hash(merge_hash)
146
159
  super({weight_initializer: @weight_initializer.to_hash,
147
160
  bias_initializer: @bias_initializer.to_hash,
@@ -153,7 +166,7 @@ module DNN
153
166
 
154
167
  def init_params
155
168
  @weight_initializer.init_param(self, @weight)
156
- @bias_initializer.init_param(self, @bias)
169
+ @bias_initializer.init_param(self, @bias) if @bias
157
170
  end
158
171
  end
159
172
 
@@ -168,7 +181,8 @@ module DNN
168
181
  weight_initializer: Utils.load_hash(hash[:weight_initializer]),
169
182
  bias_initializer: Utils.load_hash(hash[:bias_initializer]),
170
183
  l1_lambda: hash[:l1_lambda],
171
- l2_lambda: hash[:l2_lambda])
184
+ l2_lambda: hash[:l2_lambda],
185
+ use_bias: hash[:use_bias])
172
186
  end
173
187
 
174
188
  # @param [Integer] num_nodes number of nodes.
@@ -176,20 +190,23 @@ module DNN
176
190
  weight_initializer: Initializers::RandomNormal.new,
177
191
  bias_initializer: Initializers::Zeros.new,
178
192
  l1_lambda: 0,
179
- l2_lambda: 0)
193
+ l2_lambda: 0,
194
+ use_bias: true)
180
195
  super(weight_initializer: weight_initializer, bias_initializer: bias_initializer,
181
- l1_lambda: l1_lambda, l2_lambda: l2_lambda)
196
+ l1_lambda: l1_lambda, l2_lambda: l2_lambda, use_bias: use_bias)
182
197
  @num_nodes = num_nodes
183
198
  end
184
199
 
185
200
  def forward(x)
186
201
  @x = x
187
- @x.dot(@weight.data) + @bias.data
202
+ out = x.dot(@weight.data)
203
+ out += @bias.data if @bias
204
+ out
188
205
  end
189
206
 
190
207
  def backward(dout)
191
208
  @weight.grad = @x.transpose.dot(dout)
192
- @bias.grad = dout.sum(0)
209
+ @bias.grad = dout.sum(0) if @bias
193
210
  dout.dot(@weight.data.transpose)
194
211
  end
195
212
 
@@ -208,7 +225,7 @@ module DNN
208
225
  def init_params
209
226
  num_prev_nodes = @input_shape[0]
210
227
  @weight.data = Xumo::SFloat.new(num_prev_nodes, @num_nodes)
211
- @bias.data = Xumo::SFloat.new(@num_nodes)
228
+ @bias.data = Xumo::SFloat.new(@num_nodes) if @bias
212
229
  super()
213
230
  end
214
231
  end
@@ -100,8 +100,12 @@ module DNN
100
100
 
101
101
 
102
102
  class SoftmaxCrossEntropy < Loss
103
+ def self.softmax(x)
104
+ NMath.exp(x) / NMath.exp(x).sum(1).reshape(x.shape[0], 1)
105
+ end
106
+
103
107
  def loss(x, y)
104
- @out = Utils.softmax(x)
108
+ @out = SoftmaxCrossEntropy.softmax(x)
105
109
  batch_size = y.shape[0]
106
110
  -(y * NMath.log(@out + 1e-7)).sum / batch_size
107
111
  end
@@ -113,10 +117,14 @@ module DNN
113
117
 
114
118
 
115
119
  class SigmoidCrossEntropy < Loss
120
+ def initialize
121
+ @sigmoid = Sigmoid.new
122
+ end
123
+
116
124
  def loss(x, y)
117
- @out = Utils.sigmoid(x)
125
+ @out = @sigmoid.forward(x)
118
126
  batch_size = y.shape[0]
119
- -(y * NMath.log(@out + 1e-7) + (1 - y) * NMath.log(1 - @out + 1e-7)).sum / batch_size
127
+ -(y * NMath.log(@out + 1e-7) + (1 - y) * NMath.log(1 - @out + 1e-7))
120
128
  end
121
129
 
122
130
  def backward(y)
@@ -213,8 +213,10 @@ module DNN
213
213
  puts "【 epoch #{epoch}/#{epochs} 】" if verbose
214
214
  (num_train_datas.to_f / batch_size).ceil.times do |index|
215
215
  x_batch, y_batch = dataset.get_batch(batch_size)
216
- loss = train_on_batch(x_batch, y_batch, &batch_proc)
217
- if loss.nan?
216
+ loss_value = train_on_batch(x_batch, y_batch, &batch_proc)
217
+ if loss_value.is_a?(Numo::SFloat)
218
+ loss_value = loss_value.mean
219
+ elsif loss_value.nan?
218
220
  puts "\nloss is nan" if verbose
219
221
  return
220
222
  end
@@ -230,7 +232,7 @@ module DNN
230
232
  log << "_"
231
233
  end
232
234
  end
233
- log << " #{num_trained_datas}/#{num_train_datas} loss: #{sprintf('%.8f', loss)}"
235
+ log << " #{num_trained_datas}/#{num_train_datas} loss: #{sprintf('%.8f', loss_value)}"
234
236
  print log if verbose
235
237
  end
236
238
  if verbose && test
@@ -246,6 +248,7 @@ module DNN
246
248
  # Compile the model before use this method.
247
249
  # @param [Numo::SFloat] x Input training data.
248
250
  # @param [Numo::SFloat] y Output training data.
251
+ # @return [Float | Numo::SFloat] Return loss value in the form of Float or Numo::SFloat.
249
252
  # @yield [x, y] batch_proc Set proc to process per batch.
250
253
  def train_on_batch(x, y, &batch_proc)
251
254
  raise DNN_Error.new("The model is not compiled.") unless compiled?
@@ -304,7 +307,7 @@ module DNN
304
307
  # @param [Numo::SFloat] x Input data. However, x is single data.
305
308
  def predict1(x)
306
309
  check_xy_type(x)
307
- predict(Xumo::SFloat.cast([x]))[0, false]
310
+ predict(x.reshape(1, *x.shape))[0, false]
308
311
  end
309
312
 
310
313
  # @return [DNN::Model] Copy this model.
@@ -333,7 +336,7 @@ module DNN
333
336
 
334
337
  # TODO
335
338
  # It is not good to write the Layer class name directly in the Model class. I will fix it later.
336
- def forward(x, learning_phase)01
339
+ def forward(x, learning_phase)
337
340
  @layers.each do |layer|
338
341
  x = if layer.is_a?(Layers::Dropout) || layer.is_a?(Layers::BatchNormalization) || layer.is_a?(Model)
339
342
  layer.forward(x, learning_phase)
@@ -18,9 +18,10 @@ module DNN
18
18
  weight_initializer: RandomNormal.new,
19
19
  bias_initializer: Zeros.new,
20
20
  l1_lambda: 0,
21
- l2_lambda: 0)
21
+ l2_lambda: 0,
22
+ use_bias: true)
22
23
  super(weight_initializer: weight_initializer, bias_initializer: bias_initializer,
23
- l1_lambda: l1_lambda, l2_lambda: l2_lambda)
24
+ l1_lambda: l1_lambda, l2_lambda: l2_lambda, use_bias: use_bias)
24
25
  @num_nodes = num_nodes
25
26
  @stateful = stateful
26
27
  @return_sequences = return_sequences
@@ -47,7 +48,7 @@ module DNN
47
48
  def backward(dh2s)
48
49
  @weight.grad = Xumo::SFloat.zeros(*@weight.data.shape)
49
50
  @weight2.grad = Xumo::SFloat.zeros(*@weight2.data.shape)
50
- @bias.grad = Xumo::SFloat.zeros(*@bias.data.shape)
51
+ @bias.grad = Xumo::SFloat.zeros(*@bias.data.shape) if @bias
51
52
  unless @return_sequences
52
53
  dh = dh2s
53
54
  dh2s = Xumo::SFloat.zeros(dh.shape[0], @time_length, dh.shape[1])
@@ -114,7 +115,8 @@ module DNN
114
115
  def forward(x, h)
115
116
  @x = x
116
117
  @h = h
117
- h2 = x.dot(@weight.data) + h.dot(@weight2.data) + @bias.data
118
+ h2 = x.dot(@weight.data) + h.dot(@weight2.data)
119
+ h2 += @bias.data if @bias
118
120
  @activation.forward(h2)
119
121
  end
120
122
 
@@ -122,7 +124,7 @@ module DNN
122
124
  dh2 = @activation.backward(dh2)
123
125
  @weight.grad += @x.transpose.dot(dh2)
124
126
  @weight2.grad += @h.transpose.dot(dh2)
125
- @bias.grad += dh2.sum(0)
127
+ @bias.grad += dh2.sum(0) if @bias
126
128
  dx = dh2.dot(@weight.data.transpose)
127
129
  dh = dh2.dot(@weight2.data.transpose)
128
130
  [dx, dh]
@@ -143,7 +145,8 @@ module DNN
143
145
  weight_initializer: Utils.load_hash(hash[:weight_initializer]),
144
146
  bias_initializer: Utils.load_hash(hash[:bias_initializer]),
145
147
  l1_lambda: hash[:l1_lambda],
146
- l2_lambda: hash[:l2_lambda])
148
+ l2_lambda: hash[:l2_lambda],
149
+ use_bias: hash[:use_bias])
147
150
  simple_rnn
148
151
  end
149
152
 
@@ -154,14 +157,16 @@ module DNN
154
157
  weight_initializer: RandomNormal.new,
155
158
  bias_initializer: Zeros.new,
156
159
  l1_lambda: 0,
157
- l2_lambda: 0)
160
+ l2_lambda: 0,
161
+ use_bias: true)
158
162
  super(num_nodes,
159
163
  stateful: stateful,
160
164
  return_sequences: return_sequences,
161
165
  weight_initializer: weight_initializer,
162
166
  bias_initializer: bias_initializer,
163
167
  l1_lambda: l1_lambda,
164
- l2_lambda: l2_lambda)
168
+ l2_lambda: l2_lambda,
169
+ use_bias: use_bias)
165
170
  @activation = activation
166
171
  end
167
172
 
@@ -176,10 +181,10 @@ module DNN
176
181
  num_prev_nodes = @input_shape[1]
177
182
  @weight.data = Xumo::SFloat.new(num_prev_nodes, @num_nodes)
178
183
  @weight2.data = Xumo::SFloat.new(@num_nodes, @num_nodes)
179
- @bias.data = Xumo::SFloat.new(@num_nodes)
184
+ @bias.data = Xumo::SFloat.new(@num_nodes) if @bias
180
185
  @weight_initializer.init_param(self, @weight)
181
186
  @weight_initializer.init_param(self, @weight2)
182
- @bias_initializer.init_param(self, @bias)
187
+ @bias_initializer.init_param(self, @bias) if @bias
183
188
  @time_length.times do |t|
184
189
  @layers << SimpleRNN_Dense.new(@weight, @weight2, @bias, @activation)
185
190
  end
@@ -204,7 +209,8 @@ module DNN
204
209
  @h = h
205
210
  @c = c
206
211
  num_nodes = h.shape[1]
207
- a = x.dot(@weight.data) + h.dot(@weight2.data) + @bias.data
212
+ a = x.dot(@weight.data) + h.dot(@weight2.data)
213
+ a += @bias.data if @bias
208
214
 
209
215
  @forget = @forget_sigmoid.forward(a[true, 0...num_nodes])
210
216
  @g = @g_tanh.forward(a[true, num_nodes...(num_nodes * 2)])
@@ -230,7 +236,7 @@ module DNN
230
236
 
231
237
  @weight.grad += @x.transpose.dot(da)
232
238
  @weight2.grad += @h.transpose.dot(da)
233
- @bias.grad += da.sum(0)
239
+ @bias.grad += da.sum(0) if @bias
234
240
  dx = da.dot(@weight.data.transpose)
235
241
  dh = da.dot(@weight2.data.transpose)
236
242
  dc = dc2_tmp * @forget
@@ -247,7 +253,8 @@ module DNN
247
253
  weight_initializer: Utils.load_hash(hash[:weight_initializer]),
248
254
  bias_initializer: Utils.load_hash(hash[:bias_initializer]),
249
255
  l1_lambda: hash[:l1_lambda],
250
- l2_lambda: hash[:l2_lambda])
256
+ l2_lambda: hash[:l2_lambda],
257
+ use_bias: hash[:use_bias])
251
258
  lstm
252
259
  end
253
260
 
@@ -257,7 +264,8 @@ module DNN
257
264
  weight_initializer: RandomNormal.new,
258
265
  bias_initializer: Zeros.new,
259
266
  l1_lambda: 0,
260
- l2_lambda: 0)
267
+ l2_lambda: 0,
268
+ use_bias: true)
261
269
  super
262
270
  @cell = @params[:c] = Param.new
263
271
  end
@@ -286,7 +294,7 @@ module DNN
286
294
  def backward(dh2s)
287
295
  @weight.grad = Xumo::SFloat.zeros(*@weight.data.shape)
288
296
  @weight2.grad = Xumo::SFloat.zeros(*@weight2.data.shape)
289
- @bias.grad = Xumo::SFloat.zeros(*@bias.data.shape)
297
+ @bias.grad = Xumo::SFloat.zeros(*@bias.data.shape) if @bias
290
298
  unless @return_sequences
291
299
  dh = dh2s
292
300
  dh2s = Xumo::SFloat.zeros(dh.shape[0], @time_length, dh.shape[1])
@@ -315,10 +323,10 @@ module DNN
315
323
  num_prev_nodes = @input_shape[1]
316
324
  @weight.data = Xumo::SFloat.new(num_prev_nodes, @num_nodes * 4)
317
325
  @weight2.data = Xumo::SFloat.new(@num_nodes, @num_nodes * 4)
318
- @bias.data = Xumo::SFloat.new(@num_nodes * 4)
326
+ @bias.data = Xumo::SFloat.new(@num_nodes * 4) if @bias
319
327
  @weight_initializer.init_param(self, @weight)
320
328
  @weight_initializer.init_param(self, @weight2)
321
- @bias_initializer.init_param(self, @bias)
329
+ @bias_initializer.init_param(self, @bias) if @bias
322
330
  @time_length.times do |t|
323
331
  @layers << LSTM_Dense.new(@weight, @weight2, @bias)
324
332
  end
@@ -342,15 +350,19 @@ module DNN
342
350
  num_nodes = h.shape[1]
343
351
  @weight_a = @weight.data[true, 0...(num_nodes * 2)]
344
352
  @weight2_a = @weight2.data[true, 0...(num_nodes * 2)]
345
- bias_a = @bias.data[0...(num_nodes * 2)]
346
- a = x.dot(@weight_a) + h.dot(@weight2_a) + bias_a
353
+ a = x.dot(@weight_a) + h.dot(@weight2_a)
354
+ a += @bias.data[0...(num_nodes * 2)] if @bias
347
355
  @update = @update_sigmoid.forward(a[true, 0...num_nodes])
348
356
  @reset = @reset_sigmoid.forward(a[true, num_nodes..-1])
349
357
 
350
358
  @weight_h = @weight.data[true, (num_nodes * 2)..-1]
351
359
  @weight2_h = @weight2.data[true, (num_nodes * 2)..-1]
352
- bias_h = @bias.data[(num_nodes * 2)..-1]
353
- @tanh_h = @tanh.forward(x.dot(@weight_h) + (h * @reset).dot(@weight2_h) + bias_h)
360
+ @tanh_h = if @bias
361
+ bias_h = @bias.data[(num_nodes * 2)..-1]
362
+ @tanh.forward(x.dot(@weight_h) + (h * @reset).dot(@weight2_h) + bias_h)
363
+ else
364
+ @tanh.forward(x.dot(@weight_h) + (h * @reset).dot(@weight2_h))
365
+ end
354
366
  h2 = (1 - @update) * h + @update * @tanh_h
355
367
  h2
356
368
  end
@@ -363,7 +375,7 @@ module DNN
363
375
  dx = dtanh_h.dot(@weight_h.transpose)
364
376
  dweight2_h = (@h * @reset).transpose.dot(dtanh_h)
365
377
  dh += dtanh_h.dot(@weight2_h.transpose) * @reset
366
- dbias_h = dtanh_h.sum(0)
378
+ dbias_h = dtanh_h.sum(0) if @bias
367
379
 
368
380
  dreset = @reset_sigmoid.backward(dtanh_h.dot(@weight2_h.transpose) * @h)
369
381
  dupdate = @update_sigmoid.backward(dh2 * @tanh_h - dh2 * @h)
@@ -372,11 +384,11 @@ module DNN
372
384
  dx += da.dot(@weight_a.transpose)
373
385
  dweight2_a = @h.transpose.dot(da)
374
386
  dh += da.dot(@weight2_a.transpose)
375
- dbias_a = da.sum(0)
387
+ dbias_a = da.sum(0) if @bias
376
388
 
377
389
  @weight.grad += Xumo::SFloat.hstack([dweight_a, dweight_h])
378
390
  @weight2.grad += Xumo::SFloat.hstack([dweight2_a, dweight2_h])
379
- @bias.grad += Xumo::SFloat.hstack([dbias_a, dbias_h])
391
+ @bias.grad += Xumo::SFloat.hstack([dbias_a, dbias_h]) if @bias
380
392
  [dx, dh]
381
393
  end
382
394
  end
@@ -390,7 +402,8 @@ module DNN
390
402
  weight_initializer: Utils.load_hash(hash[:weight_initializer]),
391
403
  bias_initializer: Utils.load_hash(hash[:bias_initializer]),
392
404
  l1_lambda: hash[:l1_lambda],
393
- l2_lambda: hash[:l2_lambda])
405
+ l2_lambda: hash[:l2_lambda],
406
+ use_bias: hash[:use_bias])
394
407
  gru
395
408
  end
396
409
 
@@ -400,7 +413,8 @@ module DNN
400
413
  weight_initializer: RandomNormal.new,
401
414
  bias_initializer: Zeros.new,
402
415
  l1_lambda: 0,
403
- l2_lambda: 0)
416
+ l2_lambda: 0,
417
+ use_bias: true)
404
418
  super
405
419
  end
406
420
 
@@ -411,10 +425,10 @@ module DNN
411
425
  num_prev_nodes = @input_shape[1]
412
426
  @weight.data = Xumo::SFloat.new(num_prev_nodes, @num_nodes * 3)
413
427
  @weight2.data = Xumo::SFloat.new(@num_nodes, @num_nodes * 3)
414
- @bias.data = Xumo::SFloat.new(@num_nodes * 3)
428
+ @bias.data = Xumo::SFloat.new(@num_nodes * 3) if @bias
415
429
  @weight_initializer.init_param(self, @weight)
416
430
  @weight_initializer.init_param(self, @weight2)
417
- @bias_initializer.init_param(self, @bias)
431
+ @bias_initializer.init_param(self, @bias) if @bias
418
432
  @time_length.times do |t|
419
433
  @layers << GRU_Dense.new(@weight, @weight2, @bias)
420
434
  end
@@ -20,14 +20,14 @@ module DNN
20
20
  dnn_class.new
21
21
  end
22
22
 
23
- # TODO
24
- # Don't want to write an implementation of the activation function in utils, so we will consider it later.
23
+ # Return the result of the sigmoid function.
25
24
  def self.sigmoid(x)
26
- 1 / (1 + NMath.exp(-x))
25
+ Sigmoid.new.forward(x)
27
26
  end
28
27
 
28
+ # Return the result of the softmax function.
29
29
  def self.softmax(x)
30
- NMath.exp(x) / NMath.exp(x).sum(1).reshape(x.shape[0], 1)
30
+ SoftmaxCrossEntropy.softmax(x)
31
31
  end
32
32
  end
33
33
  end
@@ -0,0 +1,60 @@
1
+ require "csv"
2
+ require_relative "downloader"
3
+
4
+ module DNN
5
+ class DNN_Iris_LoadError < DNN_Error; end
6
+
7
+ module Iris
8
+ URL_CSV = "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
9
+
10
+ # Iris-setosa
11
+ SETOSA = 0
12
+ # Iris-versicolor
13
+ VERSICOLOR = 1
14
+ # Iris-virginica
15
+ VIRGINICA = 2
16
+
17
+ def self.downloads
18
+ return if File.exist?(url_to_file_name(URL_CSV))
19
+ Downloader.download(URL_CSV)
20
+ end
21
+
22
+ def self.load(shuffle = false, shuffle_seed = rand(1 << 31))
23
+ downloads
24
+ csv_array = CSV.read(url_to_file_name(URL_CSV)).select { |a| a.length > 0 }
25
+ x = Numo::SFloat.zeros(csv_array.length, 4)
26
+ y = Numo::SFloat.zeros(csv_array.length)
27
+ csv_array.each.with_index do |(sepal_length, sepal_width, petal_length, petal_width, classes), i|
28
+ x[i, 0] = sepal_length.to_f
29
+ x[i, 1] = sepal_width.to_f
30
+ x[i, 2] = petal_length.to_f
31
+ x[i, 3] = petal_width.to_f
32
+ y[i] = case classes
33
+ when "Iris-setosa"
34
+ SETOSA
35
+ when "Iris-versicolor"
36
+ VERSICOLOR
37
+ when "Iris-virginica"
38
+ VIRGINICA
39
+ else
40
+ raise DNN_Iris_LoadError.new("Unknown class name '#{classes}' for iris")
41
+ end
42
+ end
43
+ if shuffle
44
+ orig_seed = Random::DEFAULT.seed
45
+ srand(shuffle_seed)
46
+ indexs = (0...csv_array.length).to_a.shuffle
47
+ x[indexs, true] = x
48
+ y[indexs] = y
49
+ srand(orig_seed)
50
+ end
51
+ [x, y]
52
+ end
53
+
54
+ private_class_method
55
+
56
+ def self.url_to_file_name(url)
57
+ __dir__ + "/" + url.match(%r`.+/(.+)$`)[1]
58
+ end
59
+ end
60
+ end
data/lib/dnn/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module DNN
2
- VERSION = "0.9.3"
2
+ VERSION = "0.9.4"
3
3
  end
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.9.3
4
+ version: 0.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - unagiootoro
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-05-08 00:00:00.000000000 Z
11
+ date: 2019-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: numo-narray
@@ -101,6 +101,7 @@ files:
101
101
  - bin/console
102
102
  - bin/setup
103
103
  - examples/cifar10_example.rb
104
+ - examples/iris_example.rb
104
105
  - examples/mnist_conv2d_example.rb
105
106
  - examples/mnist_example.rb
106
107
  - examples/mnist_lstm_example.rb
@@ -126,6 +127,7 @@ files:
126
127
  - lib/dnn/lib/cifar10.rb
127
128
  - lib/dnn/lib/downloader.rb
128
129
  - lib/dnn/lib/image.rb
130
+ - lib/dnn/lib/iris.rb
129
131
  - lib/dnn/lib/mnist.rb
130
132
  - lib/dnn/version.rb
131
133
  - ruby-dnn.gemspec