rann 0.2.7 → 0.2.8
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/CHANGES.md +43 -0
- data/Gemfile.lock +1 -1
- data/examples/step_by_step.rb +57 -0
- data/lib/rann.rb +3 -0
- data/lib/rann/backprop.rb +53 -36
- data/lib/rann/connection.rb +3 -2
- data/lib/rann/gradient_checker.rb +7 -5
- data/lib/rann/lstm.rb +24 -30
- data/lib/rann/network.rb +18 -4
- data/lib/rann/neuron.rb +4 -3
- data/lib/rann/optimisers/adagrad.rb +2 -2
- data/lib/rann/optimisers/rmsprop.rb +2 -2
- data/lib/rann/product_neuron.rb +1 -1
- data/lib/rann/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2cd393e231a8a1da7a732eff0ea1e82008cc5dcc
|
4
|
+
data.tar.gz: 479d4669daab9e8f2fd60b06044d754e78479ad9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/Gemfile.lock
CHANGED
@@ -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
|
data/lib/rann.rb
CHANGED
data/lib/rann/backprop.rb
CHANGED
@@ -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
|
15
|
+
sig: ->(x){ x * (1 - x) },
|
16
16
|
linear: ->(_){ 1.to_d },
|
17
|
-
tanh: ->(x){ 1 - x
|
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
|
63
|
+
group_avg_gradients[cid] += g / batch_size
|
64
64
|
end
|
65
|
-
group_avg_error += error
|
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] =
|
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
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
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])
|
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
|
data/lib/rann/connection.rb
CHANGED
@@ -25,7 +25,7 @@ module RANN
|
|
25
25
|
|
26
26
|
def process
|
27
27
|
if processable? && !processed?
|
28
|
-
out_value = input_neuron.value
|
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
|
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
|
-
|
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] +
|
12
|
+
thetaplus[i] = thetaplus[i] + epsilon
|
11
13
|
thetaminus = network.params.dup
|
12
|
-
thetaminus[i] = thetaminus[i] -
|
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)
|
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])
|
38
|
+
total_squared_error += (targets[i] - outputs[i]) ** 2 / 2
|
37
39
|
end
|
38
40
|
|
39
41
|
total_squared_error
|
data/lib/rann/lstm.rb
CHANGED
@@ -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
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
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
|
64
|
-
@network.add RANN::LockedConnection.new
|
65
|
-
@network.add RANN::LockedConnection.new memory_context,
|
66
|
-
@network.add RANN::LockedConnection.new
|
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::
|
75
|
+
@network.add RANN::Connection.new neuron, input
|
82
76
|
end
|
83
77
|
end
|
84
78
|
end
|
data/lib/rann/network.rb
CHANGED
@@ -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
|
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
|
172
|
-
to = 1.to_d
|
173
|
-
c.weight = (to - 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
|
data/lib/rann/neuron.rb
CHANGED
@@ -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
|
9
|
-
tanh: ->(v){ Math.tanh(v).to_d(
|
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?
|
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
|
15
|
+
@historical_gradient[cid] = @historical_gradient[cid] + grad ** 2
|
16
16
|
|
17
|
-
grad
|
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
|
16
|
+
@historical_gradient[cid] = @decay * @historical_gradient[cid] + (1 - @decay) * grad ** 2
|
17
17
|
|
18
|
-
grad
|
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
|
data/lib/rann/product_neuron.rb
CHANGED
data/lib/rann/version.rb
CHANGED
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.
|
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-
|
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
|