ruby-dnn 0.13.4 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -32,7 +32,7 @@ module DNN
32
32
  if DNN.learning_phase
33
33
  mean = x.mean(axis: @axis, keepdims: true)
34
34
  @xc = x - mean
35
- var = (@xc ** 2).mean(axis: @axis, keepdims: true)
35
+ var = (@xc**2).mean(axis: @axis, keepdims: true)
36
36
  @std = Xumo::NMath.sqrt(var + @eps)
37
37
  xn = @xc / @std
38
38
  @xn = xn
@@ -53,7 +53,7 @@ module DNN
53
53
  end
54
54
  dxn = @gamma.data * dy
55
55
  dxc = dxn / @std
56
- dstd = -((dxn * @xc) / (@std ** 2)).sum(axis: @axis, keepdims: true)
56
+ dstd = -((dxn * @xc) / (@std**2)).sum(axis: @axis, keepdims: true)
57
57
  dvar = 0.5 * dstd / @std
58
58
  dxc += (2.0 / batch_size) * @xc * dvar
59
59
  dmean = dxc.sum(axis: @axis, keepdims: true)
@@ -10,13 +10,14 @@ module DNN
10
10
  return nil unless hash
11
11
  optimizer_class = DNN.const_get(hash[:class])
12
12
  optimizer = optimizer_class.allocate
13
- raise DNN_Error.new("#{optimizer.class} is not an instance of #{self} class.") unless optimizer.is_a?(self)
13
+ raise DNN_Error, "#{optimizer.class} is not an instance of #{self} class." unless optimizer.is_a?(self)
14
14
  optimizer.load_hash(hash)
15
15
  optimizer
16
16
  end
17
17
 
18
18
  def self.load(dumped)
19
19
  opt = from_hash(dumped[:hash])
20
+ return opt unless dumped[:status]
20
21
  dumped[:status].each do |key, state|
21
22
  state = state.clone
22
23
  opt.status[key] = state
@@ -34,7 +35,7 @@ module DNN
34
35
  def update(layers)
35
36
  target_params = layers.select { |layer| layer.is_a?(Layers::HasParamLayer) && layer.trainable }
36
37
  .map { |layer| layer.get_params.values }.flatten.compact
37
- .select { |param| param.grad }
38
+ .select(&:grad)
38
39
  clip_grads(target_params) if @clip_norm
39
40
  update_params(target_params)
40
41
  target_params.each do |param|
@@ -42,8 +43,9 @@ module DNN
42
43
  end
43
44
  end
44
45
 
45
- def dump
46
- { hash: to_hash, status: @status }
46
+ def dump(require_status = true)
47
+ status = require_status ? @status : nil
48
+ { hash: to_hash, status: status }
47
49
  end
48
50
 
49
51
  def to_hash(merge_hash = nil)
@@ -54,12 +56,13 @@ module DNN
54
56
 
55
57
  # Update params.
56
58
  private def update_params(params)
57
- raise NotImplementedError.new("Class '#{self.class.name}' has implement method 'update_params'")
59
+ raise NotImplementedError, "Class '#{self.class.name}' has implement method 'update_params'"
58
60
  end
59
61
 
60
62
  private def clip_grads(params)
61
- norm = Math.sqrt(params.reduce(0) { |total, param| total + (param.grad ** 2).sum })
63
+ norm = Math.sqrt(params.reduce(0) { |total, param| total + (param.grad**2).sum })
62
64
  return if norm <= @clip_norm
65
+
63
66
  rate = @clip_norm / (norm + 1e-7)
64
67
  params.each do |param|
65
68
  param.grad *= rate
@@ -71,7 +74,6 @@ module DNN
71
74
  end
72
75
  end
73
76
 
74
-
75
77
  class SGD < Optimizer
76
78
  attr_accessor :lr
77
79
  attr_accessor :momentum
@@ -107,7 +109,6 @@ module DNN
107
109
  end
108
110
  end
109
111
 
110
-
111
112
  class Nesterov < SGD
112
113
  def initialize(lr = 0.01, momentum: 0.9, clip_norm: nil)
113
114
  super(lr, momentum: momentum, clip_norm: clip_norm)
@@ -118,12 +119,11 @@ module DNN
118
119
  @v[param.name] ||= Xumo::SFloat.zeros(*param.data.shape)
119
120
  amount = param.grad * @lr
120
121
  @v[param.name] = @v[param.name] * @momentum - amount
121
- param.data = (param.data + @momentum ** 2 * @v[param.name]) - (1 + @momentum) * amount
122
+ param.data = (param.data + @momentum**2 * @v[param.name]) - (1 + @momentum) * amount
122
123
  end
123
124
  end
124
125
  end
125
126
 
126
-
127
127
  class AdaGrad < Optimizer
128
128
  attr_accessor :lr
129
129
  attr_accessor :eps
@@ -141,7 +141,7 @@ module DNN
141
141
  private def update_params(params)
142
142
  params.each do |param|
143
143
  @g[param.name] ||= Xumo::SFloat.zeros(*param.data.shape)
144
- @g[param.name] += param.grad ** 2
144
+ @g[param.name] += param.grad**2
145
145
  param.data -= (@lr / Xumo::NMath.sqrt(@g[param.name] + @eps)) * param.grad
146
146
  end
147
147
  end
@@ -155,7 +155,6 @@ module DNN
155
155
  end
156
156
  end
157
157
 
158
-
159
158
  class RMSProp < Optimizer
160
159
  attr_accessor :lr
161
160
  attr_accessor :alpha
@@ -180,7 +179,7 @@ module DNN
180
179
  private def update_params(params)
181
180
  params.each do |param|
182
181
  @g[param.name] ||= Xumo::SFloat.zeros(*param.data.shape)
183
- @g[param.name] = @alpha * @g[param.name] + (1 - @alpha) * param.grad ** 2
182
+ @g[param.name] = @alpha * @g[param.name] + (1 - @alpha) * param.grad**2
184
183
  param.data -= (@lr / Xumo::NMath.sqrt(@g[param.name] + @eps)) * param.grad
185
184
  end
186
185
  end
@@ -190,7 +189,6 @@ module DNN
190
189
  end
191
190
  end
192
191
 
193
-
194
192
  class AdaDelta < Optimizer
195
193
  attr_accessor :rho
196
194
  attr_accessor :eps
@@ -214,9 +212,9 @@ module DNN
214
212
  params.each do |param|
215
213
  @h[param.name] ||= Xumo::SFloat.zeros(*param.data.shape)
216
214
  @s[param.name] ||= Xumo::SFloat.zeros(*param.data.shape)
217
- @h[param.name] = @rho * @h[param.name] + (1 - @rho) * param.grad ** 2
215
+ @h[param.name] = @rho * @h[param.name] + (1 - @rho) * param.grad**2
218
216
  v = (Xumo::NMath.sqrt(@s[param.name] + @eps) / Xumo::NMath.sqrt(@h[param.name] + @eps)) * param.grad
219
- @s[param.name] = @rho * @s[param.name] + (1 - @rho) * v ** 2
217
+ @s[param.name] = @rho * @s[param.name] + (1 - @rho) * v**2
220
218
  param.data -= v
221
219
  end
222
220
  end
@@ -226,7 +224,6 @@ module DNN
226
224
  end
227
225
  end
228
226
 
229
-
230
227
  class RMSPropGraves < Optimizer
231
228
  attr_accessor :lr
232
229
  attr_accessor :alpha
@@ -254,8 +251,8 @@ module DNN
254
251
  @m[param.name] ||= Xumo::SFloat.zeros(*param.data.shape)
255
252
  @v[param.name] ||= Xumo::SFloat.zeros(*param.data.shape)
256
253
  @m[param.name] = @alpha * @m[param.name] + (1 - @alpha) * param.grad
257
- @v[param.name] = @alpha * @v[param.name] + (1 - @alpha) * param.grad ** 2
258
- param.data -= (@lr / Xumo::NMath.sqrt(@v[param.name] - @m[param.name] ** 2 + @eps)) * param.grad
254
+ @v[param.name] = @alpha * @v[param.name] + (1 - @alpha) * param.grad**2
255
+ param.data -= (@lr / Xumo::NMath.sqrt(@v[param.name] - @m[param.name]**2 + @eps)) * param.grad
259
256
  end
260
257
  end
261
258
 
@@ -264,7 +261,6 @@ module DNN
264
261
  end
265
262
  end
266
263
 
267
-
268
264
  class Adam < Optimizer
269
265
  attr_accessor :alpha
270
266
  attr_accessor :beta1
@@ -300,12 +296,12 @@ module DNN
300
296
 
301
297
  private def update_params(params)
302
298
  @t += 1
303
- lr = @alpha * Math.sqrt(1 - @beta2 ** @t) / (1 - @beta1 ** @t)
299
+ lr = @alpha * Math.sqrt(1 - @beta2**@t) / (1 - @beta1**@t)
304
300
  params.each do |param|
305
301
  @m[param.name] ||= Xumo::SFloat.zeros(*param.data.shape)
306
302
  @v[param.name] ||= Xumo::SFloat.zeros(*param.data.shape)
307
303
  @m[param.name] += (1 - @beta1) * (param.grad - @m[param.name])
308
- @v[param.name] += (1 - @beta2) * (param.grad ** 2 - @v[param.name])
304
+ @v[param.name] += (1 - @beta2) * (param.grad**2 - @v[param.name])
309
305
  if @amsgrad
310
306
  @s[param.name] ||= Xumo::SFloat.zeros(*param.data.shape)
311
307
  @s[param.name] = Xumo::SFloat.maximum(@s[param.name], @v[param.name])
@@ -322,7 +318,6 @@ module DNN
322
318
  end
323
319
  end
324
320
 
325
-
326
321
  class AdaBound < Adam
327
322
  attr_accessor :final_lr
328
323
  attr_accessor :gamma
@@ -344,7 +339,7 @@ module DNN
344
339
 
345
340
  private def update_params(params)
346
341
  @t += 1
347
- lr = @alpha * Math.sqrt(1 - @beta2 ** @t) / (1 - @beta1 ** @t)
342
+ lr = @alpha * Math.sqrt(1 - @beta2**@t) / (1 - @beta1**@t)
348
343
  final_lr = @final_lr * lr / @alpha
349
344
  lower_bound = final_lr * (1 - 1 / (@gamma * @t + 1))
350
345
  upper_bound = final_lr * (1 + 1 / (@gamma * @t))
@@ -352,7 +347,7 @@ module DNN
352
347
  @m[param.name] ||= Xumo::SFloat.zeros(*param.data.shape)
353
348
  @v[param.name] ||= Xumo::SFloat.zeros(*param.data.shape)
354
349
  @m[param.name] += (1 - @beta1) * (param.grad - @m[param.name])
355
- @v[param.name] += (1 - @beta2) * (param.grad ** 2 - @v[param.name])
350
+ @v[param.name] += (1 - @beta2) * (param.grad**2 - @v[param.name])
356
351
  if @amsgrad
357
352
  @s[param.name] ||= Xumo::SFloat.zeros(*param.data.shape)
358
353
  @s[param.name] = Xumo::SFloat.maximum(@s[param.name], @v[param.name])
@@ -8,17 +8,17 @@ 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 DNN_Error.new("#{regularizer.class} is not an instance of #{self} class.") unless regularizer.is_a?(self)
11
+ raise DNN_Error, "#{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
15
15
 
16
16
  def forward(x)
17
- raise NotImplementedError.new("Class '#{self.class.name}' has implement method 'forward'")
17
+ raise NotImplementedError, "Class '#{self.class.name}' has implement method 'forward'"
18
18
  end
19
19
 
20
20
  def backward
21
- raise NotImplementedError.new("Class '#{self.class.name}' has implement method 'backward'")
21
+ raise NotImplementedError, "Class '#{self.class.name}' has implement method 'backward'"
22
22
  end
23
23
 
24
24
  def to_hash(merge_hash)
@@ -28,7 +28,7 @@ module DNN
28
28
  end
29
29
 
30
30
  def load_hash(hash)
31
- raise NotImplementedError.new("Class '#{self.class.name}' has implement method 'load_hash'")
31
+ raise NotImplementedError, "Class '#{self.class.name}' has implement method 'load_hash'"
32
32
  end
33
33
  end
34
34
 
@@ -59,7 +59,6 @@ module DNN
59
59
  end
60
60
  end
61
61
 
62
-
63
62
  class L2 < Regularizer
64
63
  attr_accessor :l2_lambda
65
64
 
@@ -69,7 +68,7 @@ module DNN
69
68
  end
70
69
 
71
70
  def forward(x)
72
- x + 0.5 * @l2_lambda * (@param.data ** 2).sum
71
+ x + 0.5 * @l2_lambda * (@param.data**2).sum
73
72
  end
74
73
 
75
74
  def backward
@@ -98,7 +97,7 @@ module DNN
98
97
 
99
98
  def forward(x)
100
99
  l1 = @l1_lambda * @param.data.abs.sum
101
- l2 = 0.5 * @l2_lambda * (@param.data ** 2).sum
100
+ l2 = 0.5 * @l2_lambda * (@param.data**2).sum
102
101
  x + l1 + l2
103
102
  end
104
103
 
@@ -40,7 +40,7 @@ module DNN
40
40
 
41
41
  def build(input_shape)
42
42
  unless input_shape.length == 2
43
- raise DNN_ShapeError.new("Input shape is #{input_shape}. But input shape must be 2 dimensional.")
43
+ raise DNN_ShapeError, "Input shape is #{input_shape}. But input shape must be 2 dimensional."
44
44
  end
45
45
  super
46
46
  @time_length = @input_shape[0]
@@ -129,7 +129,6 @@ module DNN
129
129
  end
130
130
  end
131
131
 
132
-
133
132
  class SimpleRNNDense
134
133
  attr_accessor :trainable
135
134
 
@@ -162,7 +161,6 @@ module DNN
162
161
  end
163
162
  end
164
163
 
165
-
166
164
  class SimpleRNN < RNN
167
165
  attr_reader :activation
168
166
 
@@ -170,7 +168,7 @@ module DNN
170
168
  def initialize(num_nodes,
171
169
  stateful: false,
172
170
  return_sequences: true,
173
- activation: Activations::Tanh.new,
171
+ activation: Layers::Tanh.new,
174
172
  weight_initializer: Initializers::RandomNormal.new,
175
173
  recurrent_weight_initializer: Initializers::RandomNormal.new,
176
174
  bias_initializer: Initializers::Zeros.new,
@@ -222,7 +220,6 @@ module DNN
222
220
  end
223
221
  end
224
222
 
225
-
226
223
  class LSTMDense
227
224
  attr_accessor :trainable
228
225
 
@@ -230,11 +227,11 @@ module DNN
230
227
  @weight = weight
231
228
  @recurrent_weight = recurrent_weight
232
229
  @bias = bias
233
- @tanh = Activations::Tanh.new
234
- @g_tanh = Activations::Tanh.new
235
- @forget_sigmoid = Activations::Sigmoid.new
236
- @in_sigmoid = Activations::Sigmoid.new
237
- @out_sigmoid = Activations::Sigmoid.new
230
+ @tanh = Layers::Tanh.new
231
+ @g_tanh = Layers::Tanh.new
232
+ @forget_sigmoid = Layers::Sigmoid.new
233
+ @in_sigmoid = Layers::Sigmoid.new
234
+ @out_sigmoid = Layers::Sigmoid.new
238
235
  @trainable = true
239
236
  end
240
237
 
@@ -280,7 +277,6 @@ module DNN
280
277
  end
281
278
  end
282
279
 
283
-
284
280
  class LSTM < RNN
285
281
  attr_reader :cell
286
282
 
@@ -359,7 +355,6 @@ module DNN
359
355
  end
360
356
  end
361
357
 
362
-
363
358
  class GRUDense
364
359
  attr_accessor :trainable
365
360
 
@@ -367,9 +362,9 @@ module DNN
367
362
  @weight = weight
368
363
  @recurrent_weight = recurrent_weight
369
364
  @bias = bias
370
- @update_sigmoid = Activations::Sigmoid.new
371
- @reset_sigmoid = Activations::Sigmoid.new
372
- @tanh = Activations::Tanh.new
365
+ @update_sigmoid = Layers::Sigmoid.new
366
+ @reset_sigmoid = Layers::Sigmoid.new
367
+ @tanh = Layers::Tanh.new
373
368
  @trainable = true
374
369
  end
375
370
 
@@ -387,11 +382,11 @@ module DNN
387
382
  @weight_h = @weight.data[true, (num_nodes * 2)..-1]
388
383
  @weight2_h = @recurrent_weight.data[true, (num_nodes * 2)..-1]
389
384
  @tanh_h = if @bias
390
- bias_h = @bias.data[(num_nodes * 2)..-1]
391
- @tanh.forward(x.dot(@weight_h) + (h * @reset).dot(@weight2_h) + bias_h)
392
- else
393
- @tanh.forward(x.dot(@weight_h) + (h * @reset).dot(@weight2_h))
394
- end
385
+ bias_h = @bias.data[(num_nodes * 2)..-1]
386
+ @tanh.forward(x.dot(@weight_h) + (h * @reset).dot(@weight2_h) + bias_h)
387
+ else
388
+ @tanh.forward(x.dot(@weight_h) + (h * @reset).dot(@weight2_h))
389
+ end
395
390
  h2 = (1 - @update) * @tanh_h + @update * h
396
391
  h2
397
392
  end
@@ -428,7 +423,6 @@ module DNN
428
423
  end
429
424
  end
430
425
 
431
-
432
426
  class GRU < RNN
433
427
  def initialize(num_nodes,
434
428
  stateful: false,
@@ -17,7 +17,7 @@ module DNN
17
17
  private
18
18
 
19
19
  def load_bin(bin)
20
- raise NotImplementedError.new("Class '#{self.class.name}' has implement method 'load_bin'")
20
+ raise NotImplementedError, "Class '#{self.class.name}' has implement method 'load_bin'"
21
21
  end
22
22
 
23
23
  def set_all_params_data(params_data)
@@ -30,13 +30,16 @@ module DNN
30
30
  end
31
31
  end
32
32
 
33
-
34
33
  class MarshalLoader < Loader
35
34
  private def load_bin(bin)
36
35
  data = Marshal.load(Zlib::Inflate.inflate(bin))
36
+ unless @model.class.name == data[:class]
37
+ raise DNN_Error, "Class name is not mismatch. Target model is #{@model.class.name}. But loading model is #{data[:class]}."
38
+ end
37
39
  opt = Optimizers::Optimizer.load(data[:optimizer])
38
40
  loss_func = Losses::Loss.from_hash(data[:loss_func])
39
41
  @model.setup(opt, loss_func)
42
+ @model.instance_variable_set(:@built, false)
40
43
  @model.predict1(Xumo::SFloat.zeros(*data[:input_shape]))
41
44
  set_all_params_data(data[:params])
42
45
  end
@@ -50,6 +53,7 @@ module DNN
50
53
  opt = Optimizers::Optimizer.from_hash(data[:optimizer])
51
54
  loss_func = Losses::Loss.from_hash(data[:loss_func])
52
55
  @model.setup(opt, loss_func)
56
+ @model.instance_variable_set(:@built, false)
53
57
  @model.predict1(Xumo::SFloat.zeros(*data[:input_shape]))
54
58
  base64_to_params_data(data[:params])
55
59
  end
@@ -65,7 +69,6 @@ module DNN
65
69
 
66
70
  end
67
71
 
68
-
69
72
  module Savers
70
73
 
71
74
  class Saver
@@ -87,7 +90,7 @@ module DNN
87
90
  private
88
91
 
89
92
  def dump_bin
90
- raise NotImplementedError.new("Class '#{self.class.name}' has implement method 'dump_bin'")
93
+ raise NotImplementedError, "Class '#{self.class.name}' has implement method 'dump_bin'"
91
94
  end
92
95
 
93
96
  def get_all_params_data
@@ -98,7 +101,6 @@ module DNN
98
101
  end
99
102
  end
100
103
 
101
-
102
104
  class MarshalSaver < Saver
103
105
  def initialize(model, include_optimizer: true)
104
106
  super(model)
@@ -106,10 +108,10 @@ module DNN
106
108
  end
107
109
 
108
110
  private def dump_bin
109
- opt = @include_optimizer ? @model.optimizer.dump : @model.optimizer.class.new.dump
111
+ require_status = @include_optimizer ? true : false
110
112
  data = {
111
113
  version: VERSION, class: @model.class.name, input_shape: @model.layers.first.input_shape, params: get_all_params_data,
112
- optimizer: opt, loss_func: @model.loss_func.to_hash
114
+ optimizer: @model.optimizer.dump(require_status), loss_func: @model.loss_func.to_hash
113
115
  }
114
116
  Zlib::Deflate.deflate(Marshal.dump(data))
115
117
  end
@@ -0,0 +1,11 @@
1
+ module DNN
2
+ class Tensor
3
+ attr_reader :data
4
+ attr_accessor :link
5
+
6
+ def initialize(data, link = nil)
7
+ @data = data
8
+ @link = link
9
+ end
10
+ end
11
+ end