rann 0.2.7 → 0.2.8

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
  SHA1:
3
- metadata.gz: b604698cf3630cf7056f4b10d5b1b301292074b4
4
- data.tar.gz: a341f41f53c78db0f026948b7bad72ff04574e54
3
+ metadata.gz: 2cd393e231a8a1da7a732eff0ea1e82008cc5dcc
4
+ data.tar.gz: 479d4669daab9e8f2fd60b06044d754e78479ad9
5
5
  SHA512:
6
- metadata.gz: 3e7167b3fb0fb79d0fcd3fc7a72b59d0ab4c9d29b69e6fbc230599b11752b3b9e001c06e9bef284325974649e7f64d4f34dd05864fe1fedb9fa7786ef9d40586
7
- data.tar.gz: 6816e982c0536c21a474e377c87ca6de213b62268dfda48317d2c360972e2fa2d0f32eb491c8a088cccae8ca3bb5ef367587d601db2a7eda3d45d695a6c5ea8a
6
+ metadata.gz: 55e2b084f9477543cdc8bbb3cd415e80bfd6c3f75517b61cd1969e9070aa2045c27a6003655394414414c11155cbf042aa597d8ef4798bdf4a2ffcfedd02782e
7
+ data.tar.gz: c2ca6ed22034d63d2a256d7a898b8c5c3c12fcf5674d133e34e405357740ca11ba2002ad26c5506e56b861349db42c8ede21bbc22ba57957bc447b515d4bdef1
data/CHANGES.md CHANGED
@@ -1,3 +1,46 @@
1
+ - More backprop fixes..
2
+
3
+ *Michael Campbell*
4
+
5
+ - Give LSTM input neurons linear activation.
6
+
7
+ *Michael Campbell*
8
+
9
+ - For context neurons connected to a product neuron, it's initial value should
10
+ be 1.
11
+
12
+ *Michael Campbell*
13
+
14
+ - So. Many. Bugs. Turns out the product neuron stuff was still broken and
15
+ network evaluation wasn't behaving correctly with context neurons (recurrent
16
+ connections). Also an error in timestep handling during backprop, and just
17
+ generally network traversal ...
18
+
19
+ *Michael Campbell*
20
+
21
+ - Don't lock the input connections into the LSTM layer, that acts as the fully
22
+ connected part of the network and that's where the majority of learning takes
23
+ place, derp.
24
+
25
+ *Michael Campbell*
26
+
27
+ - Don't change the weight of a LockedConnection during initialisation. (eugh)
28
+
29
+ *Michael Campbell*
30
+
31
+ - Fix bug in backprop over product neuron.
32
+
33
+ *Michael Campbell*
34
+
35
+ - Worked out how to use BigDecimal properly, lol. Refactored to use
36
+ `BigDecimal.limit`.
37
+
38
+ *Michael Campbell*
39
+
40
+ - Allow customisable precision, defaults to 10.
41
+
42
+ *Michael Campbell*
43
+
1
44
  ## 0.2.7 (December 2, 2017)
2
45
 
3
46
  - Allow different weights to the different gates in the LSTM. Previously it was
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rann (0.2.7)
4
+ rann (0.2.8)
5
5
  parallel (~> 1.12, >= 1.12.0)
6
6
  ruby-graphviz (~> 1.2, >= 1.2.3)
7
7
 
@@ -0,0 +1,57 @@
1
+ # A reproduction of the wonderful step by step backprop example at
2
+ # https://mattmazur.com/2015/03/17/a-step-by-step-backpropagation-example/
3
+
4
+ require "bundler/setup"
5
+ require "rann"
6
+
7
+ # inputs
8
+ inputs = Array.new(2){ |i| RANN::Neuron.new "input #{i}", 0, :input, :sig }
9
+
10
+ # hidden layer
11
+ hiddens = Array.new(2){ |i| RANN::Neuron.new "hidden #{i}", 3, :standard, :sig }
12
+ hidden_bias = RANN::Neuron.new "bias", 0, :bias
13
+
14
+ # output layer
15
+ outputs = Array.new(2){ |i| RANN::Neuron.new "output #{i}", 3, :output, :sig }
16
+ output_bias = RANN::Neuron.new "bias", 0, :bias
17
+
18
+ # connect it all w/initial weights
19
+ connections = []
20
+ connections << RANN::Connection.new(inputs[0], hiddens[0], 0.15.to_d)
21
+ connections << RANN::Connection.new(inputs[0], hiddens[1], 0.25.to_d)
22
+ connections << RANN::Connection.new(inputs[1], hiddens[0], 0.2.to_d)
23
+ connections << RANN::Connection.new(inputs[1], hiddens[1], 0.3.to_d)
24
+ connections << RANN::Connection.new(hidden_bias, hiddens[0], 0.35.to_d)
25
+ connections << RANN::Connection.new(hidden_bias, hiddens[1], 0.35.to_d)
26
+
27
+ connections << RANN::Connection.new(hiddens[0], outputs[0], 0.4.to_d)
28
+ connections << RANN::Connection.new(hiddens[0], outputs[1], 0.5.to_d)
29
+ connections << RANN::Connection.new(hiddens[1], outputs[0], 0.45.to_d)
30
+ connections << RANN::Connection.new(hiddens[1], outputs[1], 0.55.to_d)
31
+ connections << RANN::Connection.new(output_bias, outputs[0], 0.6.to_d)
32
+ connections << RANN::Connection.new(output_bias, outputs[1], 0.6.to_d)
33
+
34
+ network = RANN::Network.new connections
35
+ backprop = RANN::Backprop.new network
36
+
37
+ inputs = [0.05.to_d, 0.10.to_d]
38
+ targets = [0.1.to_d, 0.99.to_d]
39
+ outputs = network.evaluate [0.05.to_d, 0.10.to_d]
40
+
41
+ puts "forward prop outputs: #{outputs.map(&:to_f).inspect}"
42
+
43
+ network.reset!
44
+
45
+ gradients, error =
46
+ RANN::Backprop.run_single(
47
+ network,
48
+ [0.05.to_d, 0.10.to_d],
49
+ [0.01.to_d, 0.99.to_d]
50
+ )
51
+
52
+ puts "error: #{error.to_f}"
53
+ puts "backprop gradients & updates:"
54
+ gradients.each do |cid, g|
55
+ c = network.connections.find{ |c| c.id == cid }
56
+ puts "#{c.input_neuron.name} -> #{c.output_neuron.name}: g = #{g.to_f}, u = #{(c.weight - 0.5.to_d * g).to_f}"
57
+ end
@@ -7,3 +7,6 @@ require "rann/product_neuron"
7
7
  require "rann/connection"
8
8
  require "rann/locked_connection"
9
9
  require "rann/backprop"
10
+
11
+ BigDecimal.mode BigDecimal::EXCEPTION_ALL, true
12
+ BigDecimal.limit 10
@@ -12,9 +12,9 @@ module RANN
12
12
 
13
13
  ACTIVATION_DERIVATIVES = {
14
14
  relu: ->(x){ x > 0 ? 1.to_d : 0.to_d },
15
- sig: ->(x){ x.mult(1 - x, 10) },
15
+ sig: ->(x){ x * (1 - x) },
16
16
  linear: ->(_){ 1.to_d },
17
- tanh: ->(x){ 1 - x.power(2, 10) },
17
+ tanh: ->(x){ 1 - x ** 2 },
18
18
  step: ->(_){ 0.to_d },
19
19
  }
20
20
 
@@ -60,9 +60,9 @@ module RANN
60
60
  gradients, error = Backprop.run_single network, input, targets[i + j]
61
61
 
62
62
  gradients.each do |cid, g|
63
- group_avg_gradients[cid] += g.div batch_size, 10
63
+ group_avg_gradients[cid] += g / batch_size
64
64
  end
65
- group_avg_error += error.div batch_size, 10
65
+ group_avg_error += error / batch_size
66
66
  end
67
67
 
68
68
  group_avg_gradients.default_proc = nil
@@ -113,64 +113,80 @@ module RANN
113
113
  error = mse targets, outputs
114
114
 
115
115
  # backward pass with unravelling for recurrent networks
116
- node_deltas = Hash.new{ |h, k| h[k] = Hash.new 0.to_d }
117
- gradients = Hash.new 0.to_d
118
-
116
+ node_deltas = Hash.new{ |h, k| h[k] = {} }
119
117
  initial_timestep = inputs.size - 1
120
118
  neuron_stack = network.output_neurons.map{ |n| [n, initial_timestep] }
119
+ # initialize network end-point node_deltas in all timesteps with zero
120
+ network.neurons_with_no_outgoing_connections.each do |n|
121
+ (0...(inputs.size - 1)).each do |i|
122
+ node_deltas[i][n.id] = 0.to_d
123
+ neuron_stack << [n, i]
124
+ end
125
+ end
126
+ gradients = Hash.new 0.to_d
121
127
 
122
128
  while current = neuron_stack.shift
123
129
  neuron, timestep = current
124
130
  next if node_deltas[timestep].key? neuron.id
125
131
 
126
- from_here = bptt_connecting_to neuron, network, timestep
127
- neuron_stack.push *from_here
128
-
129
132
  # neuron delta is summation of neuron deltas deltas for the connections
130
133
  # from this neuron
131
- step_one =
132
- if neuron.output?
133
- output_index = network.output_neurons.index neuron
134
- mse_delta targets[output_index], outputs[output_index]
135
- else
134
+ if neuron.output?
135
+ output_index = network.output_neurons.index neuron
136
+ step_one = mse_delta targets[output_index], outputs[output_index]
137
+ else
138
+ sum =
136
139
  network.connections_from(neuron).reduce 0.to_d do |m, c|
137
140
  out_timestep = c.output_neuron.context? ? timestep + 1 : timestep
138
141
  output_node_delta = node_deltas[out_timestep][c.output_neuron.id]
139
142
 
140
- # connection delta is the output neuron delta multiplied by the
141
- # connection's weight
142
- connection_delta =
143
- if c.output_neuron.is_a? ProductNeuron
144
- intermediate = states[out_timestep][:intermediates][c.output_neuron.id]
145
- output_node_delta.mult intermediate.div(states[timestep][:values][c.input_neuron.id], 10), 10
146
- else
147
- output_node_delta.mult c.weight, 10
148
- end
149
-
150
- m + connection_delta
143
+ if out_timestep > initial_timestep
144
+ m
145
+ elsif !output_node_delta
146
+ break
147
+ else
148
+ # connection delta is the output neuron delta multiplied by the
149
+ # connection's weight
150
+ connection_delta =
151
+ if c.output_neuron.is_a? ProductNeuron
152
+ intermediate =
153
+ network.connections_to(c.output_neuron).reject{ |c2| c2 == c }.reduce 1.to_d do |m, c2|
154
+ m * states[timestep][:values][c2.input_neuron.id] * c2.weight
155
+ end
156
+ output_node_delta * intermediate * c.weight
157
+ else
158
+ output_node_delta * c.weight
159
+ end
160
+
161
+ m + connection_delta
162
+ end
151
163
  end
152
- end
164
+
165
+ step_one = sum || next
166
+ end
167
+
168
+ from_here = bptt_connecting_to neuron, network, timestep
169
+ neuron_stack |= from_here
153
170
 
154
171
  node_delta =
155
172
  ACTIVATION_DERIVATIVES[neuron.activation_function]
156
- .call(states[timestep][:values][neuron.id])
157
- .mult(step_one, 10)
173
+ .call(states[timestep][:values][neuron.id]) *
174
+ step_one
158
175
 
159
176
  node_deltas[timestep][neuron.id] = node_delta
160
177
 
178
+ in_timestep = neuron.context? ? timestep - 1 : timestep
161
179
  network.connections_to(neuron).each do |c|
162
- in_timestep = neuron.context? ? timestep - 1 : timestep
163
-
164
180
  # connection gradient is the output neuron delta multipled by the
165
181
  # connection's input neuron value.
166
182
  gradient =
167
183
  if c.output_neuron.is_a? ProductNeuron
168
184
  intermediate = states[timestep][:intermediates][c.output_neuron.id]
169
- node_delta.mult intermediate.div(c.weight, 10), 10
185
+ node_delta * intermediate / c.weight
170
186
  elsif c.input_neuron.context? && timestep == 0
171
187
  0.to_d
172
188
  else
173
- node_delta.mult states[in_timestep][:values][c.input_neuron.id], 10
189
+ node_delta * states[in_timestep][:values][c.input_neuron.id]
174
190
  end
175
191
 
176
192
  gradients[c.id] += gradient
@@ -192,7 +208,7 @@ module RANN
192
208
  end
193
209
  end
194
210
 
195
- def restore filepath
211
+ def restore filepath = nil
196
212
  unless filepath
197
213
  filepath = Dir['*'].select{ |f| f =~ /rann_savepoint_.*/ }.sort.last
198
214
 
@@ -217,7 +233,7 @@ module RANN
217
233
  total_squared_error = 0.to_d
218
234
 
219
235
  targets.size.times do |i|
220
- total_squared_error += (targets[i] - outputs[i]).power(2, 10).div(2, 10)
236
+ total_squared_error += (targets[i] - outputs[i]) ** 2 / 2
221
237
  end
222
238
 
223
239
  total_squared_error
@@ -231,11 +247,12 @@ module RANN
231
247
  # halt traversal if we're at a context and we're at the base timestep
232
248
  return [] if neuron.context? && timestep == 0
233
249
 
250
+ timestep -= 1 if neuron.context?
251
+
234
252
  network.connections_to(neuron).each.with_object [] do |c, a|
235
253
  # don't enqueue connections from inputs
236
254
  next if c.input_neuron.input?
237
255
 
238
- timestep -= timestep if neuron.context?
239
256
  a << [c.input_neuron, timestep]
240
257
  end
241
258
  end
@@ -25,7 +25,7 @@ module RANN
25
25
 
26
26
  def process
27
27
  if processable? && !processed?
28
- out_value = input_neuron.value.mult weight, 10
28
+ out_value = input_neuron.value * weight
29
29
  output_neuron.push_value! out_value
30
30
  @processed = true
31
31
  end
@@ -60,8 +60,9 @@ module RANN
60
60
  if output_neuron.context?
61
61
  1.to_d
62
62
  else
63
- rand.to_d 10
63
+ rand.to_d BigDecimal.limit
64
64
  end
65
65
  end
66
66
  end
67
67
  end
68
+
@@ -1,15 +1,17 @@
1
1
  module RANN
2
2
  class GradientChecker
3
- EPSILON = 10.to_d.power -4, 10
3
+ def self.epsilon
4
+ 10.to_d ** -4
5
+ end
4
6
 
5
7
  def self.check network, inputs, targets, dvec
6
8
  gradapprox = []
7
9
 
8
10
  network.params.size.times do |i|
9
11
  thetaplus = network.params.dup
10
- thetaplus[i] = thetaplus[i] + EPSILON
12
+ thetaplus[i] = thetaplus[i] + epsilon
11
13
  thetaminus = network.params.dup
12
- thetaminus[i] = thetaminus[i] - EPSILON
14
+ thetaminus[i] = thetaminus[i] - epsilon
13
15
 
14
16
  network.impose thetaplus
15
17
  outputs = network.evaluate inputs
@@ -21,7 +23,7 @@ module RANN
21
23
  error_thetaminus = error outputs, targets
22
24
  network.reset!
23
25
 
24
- gradapprox[i] = (error_thetaplus - error_thetaminus).div(EPSILON.mult(2, 10), 10)
26
+ gradapprox[i] = (error_thetaplus - error_thetaminus) / (epsilon * 2)
25
27
  end
26
28
 
27
29
  gradapprox.each.with_index.with_object [] do |(ga, i), res|
@@ -33,7 +35,7 @@ module RANN
33
35
  total_squared_error = 0.to_d
34
36
 
35
37
  targets.size.times do |i|
36
- total_squared_error += (targets[i] - outputs[i]).power(2, 10).div(2, 10)
38
+ total_squared_error += (targets[i] - outputs[i]) ** 2 / 2
37
39
  end
38
40
 
39
41
  total_squared_error
@@ -19,52 +19,46 @@ module RANN
19
19
 
20
20
  def init
21
21
  @size.times do |j|
22
- input = RANN::Neuron.new("LSTM #{name} Input #{j}", 0, :standard).tap{ |n| @network.add n }
22
+ input = RANN::Neuron.new("LSTM #{name} Input #{j}", 0, :standard, :linear).tap{ |n| @network.add n }
23
23
  @inputs << input
24
24
 
25
25
  f = RANN::Neuron.new("LSTM #{name} F #{j}", 3, :standard, :sig).tap{ |n| @network.add n }
26
26
  i = RANN::Neuron.new("LSTM #{name} I #{j}", 4, :standard, :sig).tap{ |n| @network.add n }
27
27
  g = RANN::Neuron.new("LSTM #{name} G #{j}", 3, :standard, :tanh).tap{ |n| @network.add n }
28
28
  o = RANN::Neuron.new("LSTM #{name} O #{j}", 3, :standard, :sig).tap{ |n| @network.add n }
29
- bias_f = RANN::Neuron.new("LSTM #{name} Bias F #{j}", 0, :bias).tap do |n|
30
- @network.add n
31
- end
32
- bias_i = RANN::Neuron.new("LSTM #{name} Bias I #{j}", 0, :bias).tap do |n|
33
- @network.add n
34
- end
35
- bias_g = RANN::Neuron.new("LSTM #{name} Bias G #{j}", 0, :bias).tap do |n|
36
- @network.add n
37
- end
38
- bias_o = RANN::Neuron.new("LSTM #{name} Bias O #{j}", 0, :bias).tap do |n|
39
- @network.add n
40
- end
29
+ bias_f = RANN::Neuron.new("LSTM #{name} Bias F #{j}", 0, :bias).tap{ |n| @network.add n }
30
+ bias_i = RANN::Neuron.new("LSTM #{name} Bias I #{j}", 0, :bias).tap{ |n| @network.add n }
31
+ bias_g = RANN::Neuron.new("LSTM #{name} Bias G #{j}", 0, :bias).tap{ |n| @network.add n }
32
+ bias_o = RANN::Neuron.new("LSTM #{name} Bias O #{j}", 0, :bias).tap{ |n| @network.add n }
41
33
  memory_product = RANN::ProductNeuron.new("LSTM #{name} Mem Product #{j}", 2, :standard, :linear).tap{ |n| @network.add n }
42
34
  i_g_product = RANN::ProductNeuron.new("LSTM #{name} Hidden 2/3 Product #{j}", 2, :standard, :linear).tap{ |n| @network.add n }
43
35
  memory_standard = RANN::Neuron.new("LSTM #{name} Mem Standard #{j}", 2, :standard, :linear).tap{ |n| @network.add n }
44
36
  memory_tanh = RANN::Neuron.new("LSTM #{name} Mem Tanh #{j}", 1, :standard, :tanh).tap{ |n| @network.add n }
45
37
  memory_o_product = RANN::ProductNeuron.new("LSTM #{name} Mem/Hidden 4 Product #{j}", 2, :standard, :linear).tap{ |n| @network.add n }
46
- output = RANN::Neuron.new("LSTM #{name} Output #{j}", 1, :standard, :linear).tap{ |n| @network.add n }
47
- @outputs << output
48
- memory_context = RANN::Neuron.new("LSTM #{name} Mem Context #{j}", 1, :context).tap{ |n| @network.add n }
38
+ @outputs << memory_o_product
39
+ memory_context =
40
+ RANN::Neuron.new("LSTM #{name} Mem Context #{j}", 1, :context).tap do |n|
41
+ @network.add n
42
+ n.value = 1.to_d # connecting to a product neuron
43
+ end
49
44
  output_context = RANN::Neuron.new("LSTM #{name} Output Context #{j}", 1, :context).tap{ |n| @network.add n }
50
45
 
51
46
  @network.add RANN::Connection.new input, f
52
47
  @network.add RANN::Connection.new input, i
53
48
  @network.add RANN::Connection.new input, g
54
49
  @network.add RANN::Connection.new input, o
55
- @network.add RANN::LockedConnection.new f, memory_product, 1
56
- @network.add RANN::LockedConnection.new i, i_g_product, 1
57
- @network.add RANN::LockedConnection.new g, i_g_product, 1
58
- @network.add RANN::LockedConnection.new i_g_product, memory_standard, 1
59
- @network.add RANN::LockedConnection.new memory_product, memory_standard, 1
60
- @network.add RANN::LockedConnection.new memory_standard, memory_tanh, 1
61
- @network.add RANN::LockedConnection.new o, memory_o_product, 1
62
- @network.add RANN::LockedConnection.new memory_tanh, memory_o_product, 1
63
- @network.add RANN::LockedConnection.new memory_o_product, output, 1
64
- @network.add RANN::LockedConnection.new memory_standard, memory_context, 1
65
- @network.add RANN::LockedConnection.new memory_context, memory_product, 1
66
- @network.add RANN::LockedConnection.new memory_context, i, 1
67
- @network.add RANN::LockedConnection.new memory_o_product, output_context, 1
50
+ @network.add RANN::LockedConnection.new f, memory_product, 1.to_d
51
+ @network.add RANN::LockedConnection.new i, i_g_product, 1.to_d
52
+ @network.add RANN::LockedConnection.new g, i_g_product, 1.to_d
53
+ @network.add RANN::LockedConnection.new i_g_product, memory_standard, 1.to_d
54
+ @network.add RANN::LockedConnection.new memory_product, memory_standard, 1.to_d
55
+ @network.add RANN::LockedConnection.new memory_standard, memory_tanh, 1.to_d
56
+ @network.add RANN::LockedConnection.new o, memory_o_product, 1.to_d
57
+ @network.add RANN::LockedConnection.new memory_tanh, memory_o_product, 1.to_d
58
+ @network.add RANN::LockedConnection.new memory_standard, memory_context, 1.to_d
59
+ @network.add RANN::LockedConnection.new memory_context, memory_product, 1.to_d
60
+ @network.add RANN::LockedConnection.new memory_context, i, 1.to_d
61
+ @network.add RANN::LockedConnection.new memory_o_product, output_context, 1.to_d
68
62
  @network.add RANN::Connection.new output_context, f
69
63
  @network.add RANN::Connection.new output_context, i
70
64
  @network.add RANN::Connection.new output_context, g
@@ -78,7 +72,7 @@ module RANN
78
72
 
79
73
  def add_input neuron
80
74
  @inputs.each do |input|
81
- @network.add RANN::LockedConnection.new neuron, input, 1
75
+ @network.add RANN::Connection.new neuron, input
82
76
  end
83
77
  end
84
78
  end
@@ -41,7 +41,7 @@ module RANN
41
41
  # would probably be easier to detect circular dependency this way too?
42
42
  begin
43
43
  i = 0
44
- until output_neurons.all?{ |neuron| neuron.value }
44
+ until connections.select(&:enabled?).all? &:processed?
45
45
  i += 1
46
46
  connections.each do |connection|
47
47
  next if !connection.enabled?
@@ -167,11 +167,15 @@ module RANN
167
167
 
168
168
  def init_normalised!
169
169
  connections.each do |c|
170
+ next if c.locked?
171
+
170
172
  out_cons = c.output_neuron.connection_count.to_d
171
- from = -1.to_d.div out_cons.sqrt(10), 10
172
- to = 1.to_d.div out_cons.sqrt(10), 10
173
- c.weight = (to - from).mult(rand.to_d, 10) + from
173
+ from = -1.to_d / out_cons.sqrt(0)
174
+ to = 1.to_d / out_cons.sqrt(0)
175
+ c.weight = (to - from) * rand.to_d + from
174
176
  end
177
+
178
+ true
175
179
  end
176
180
  alias init_normalized! init_normalised!
177
181
 
@@ -179,6 +183,16 @@ module RANN
179
183
  neurons.each do |neuron|
180
184
  neuron.connection_count = connections.count{ |c| c.output_neuron == neuron }
181
185
  end
186
+
187
+ true
188
+ end
189
+
190
+ def neurons_with_no_outgoing_connections
191
+ return @no_outgoing if defined? @no_outgoing
192
+
193
+ neurons.select do |n|
194
+ connections_from(n).none?
195
+ end
182
196
  end
183
197
  end
184
198
  end
@@ -1,12 +1,13 @@
1
1
  require "securerandom"
2
2
  require "bigdecimal"
3
+ require "bigdecimal/math"
3
4
  require "bigdecimal/util"
4
5
 
5
6
  module RANN
6
7
  class Neuron
7
8
  ACTIVATION_FUNCTIONS = {
8
- sig: ->(v){ 1.to_d.div(1 + Math::E.to_d.power(-v, 10), 10) },
9
- tanh: ->(v){ Math.tanh(v).to_d(10) },
9
+ sig: ->(v){ 1.to_d / (1 + BigMath.E(BigDecimal.limit) ** -v) },
10
+ tanh: ->(v){ Math.tanh(v).to_d(BigDecimal.limit) },
10
11
  relu: ->(v){ [0.to_d, v].max },
11
12
  linear: ->(v){ v },
12
13
  step: ->(v){ v > 0.5 ? 1.to_d : 0.to_d },
@@ -73,7 +74,7 @@ module RANN
73
74
  end
74
75
 
75
76
  def initial_activation_function
76
- if standard? || context?
77
+ if standard?
77
78
  :relu
78
79
  else
79
80
  :linear
@@ -12,9 +12,9 @@ module RANN
12
12
  end
13
13
 
14
14
  def update grad, cid
15
- @historical_gradient[cid] = @historical_gradient[cid] + grad.power(2, 10)
15
+ @historical_gradient[cid] = @historical_gradient[cid] + grad ** 2
16
16
 
17
- grad.mult(- @learning_rate.div(@fudge_factor + @historical_gradient[cid].sqrt(10), 10), 10)
17
+ grad * - @learning_rate / (@fudge_factor + @historical_gradient[cid].sqrt(0))
18
18
  end
19
19
 
20
20
  # anything that gets modified over the course of training
@@ -13,9 +13,9 @@ module RANN
13
13
  end
14
14
 
15
15
  def update grad, cid
16
- @historical_gradient[cid] = @decay.mult(@historical_gradient[cid], 10) + (1 - @decay).mult(grad.power(2, 10), 10)
16
+ @historical_gradient[cid] = @decay * @historical_gradient[cid] + (1 - @decay) * grad ** 2
17
17
 
18
- grad.mult(- @learning_rate.div(@fudge_factor + @historical_gradient[cid].sqrt(10), 10), 10)
18
+ grad * - @learning_rate / (@fudge_factor + @historical_gradient[cid].sqrt(0))
19
19
  end
20
20
 
21
21
  # anything that gets modified over the course of training
@@ -5,7 +5,7 @@ module RANN
5
5
  attr_accessor :intermediate
6
6
 
7
7
  def set_value!
8
- @intermediate = incoming.reduce{ |i, m| m.mult(i, 10) }
8
+ @intermediate = incoming.reduce :*
9
9
  self.value = ACTIVATION_FUNCTIONS[activation_function].call @intermediate
10
10
  end
11
11
  end
@@ -1,3 +1,3 @@
1
1
  module RANN
2
- VERSION = "0.2.7"
2
+ VERSION = "0.2.8"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rann
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.2.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Campbell
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-12-02 00:00:00.000000000 Z
11
+ date: 2017-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: parallel
@@ -110,6 +110,7 @@ files:
110
110
  - bench/xor_benchmark.rb
111
111
  - bin/console
112
112
  - bin/setup
113
+ - examples/step_by_step.rb
113
114
  - examples/xor.rb
114
115
  - lib/rann.rb
115
116
  - lib/rann/backprop.rb