rb-brain 0.0.1 → 0.1.0

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: c16b832f4b21365c93b698c01c14fbea54eb2e74
4
- data.tar.gz: e65a2a8c1c76c8b83c00972184942d02fbbeefa3
3
+ metadata.gz: f43371c0a74e1690e8814ae7230dd12d6d0f1be0
4
+ data.tar.gz: ea374d2706bd4d54466201eb805c842d7478ba2d
5
5
  SHA512:
6
- metadata.gz: cabeba60da560694cb1343f0c0f384533e563ea4f829838783a5cea8ac30c81cf487e0cc2faede4d832ae6e1ea8da3156eca6b4dd7da66c9b29ae2c5be7d6a4f
7
- data.tar.gz: 80aab9ccc24424d6b1763c985ff693f81e09b6c41aa1d613d4dc46f431b438d8ce83a4468d78da67df16a5b75858c14747b67e0132b4ccc34df8de3438fab9f7
6
+ metadata.gz: 7c7e8ee3b5d5b07b99b5c6e972201487188f33f173a3b48025d317975602abe931163e05f1ee5ffef2327e8dd24019fb09c1609edf8dd049ca84fe69891b1a32
7
+ data.tar.gz: 86600d5d1c10f1e5fc796a19aaee8ee3019ea7040f0649b8a2930d0018d3b11c4b132920e92e0ed7be301222e7a32becfc1287df4ec3c2e0666a846118d3d0a3
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --require spec_helper
3
+ --format documentation
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in carrierwave-webdav.gemspec
4
4
  gemspec
5
+ gem 'rake'
6
+ gem 'rspec'
7
+ gem 'pry'
8
+ gem 'hashr'
@@ -0,0 +1,40 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rb-brain (0.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ coderay (1.1.0)
10
+ diff-lcs (1.2.5)
11
+ hashr (0.0.22)
12
+ method_source (0.8.2)
13
+ pry (0.10.1)
14
+ coderay (~> 1.1.0)
15
+ method_source (~> 0.8.1)
16
+ slop (~> 3.4)
17
+ rake (10.4.2)
18
+ rspec (3.1.0)
19
+ rspec-core (~> 3.1.0)
20
+ rspec-expectations (~> 3.1.0)
21
+ rspec-mocks (~> 3.1.0)
22
+ rspec-core (3.1.7)
23
+ rspec-support (~> 3.1.0)
24
+ rspec-expectations (3.1.2)
25
+ diff-lcs (>= 1.2.0, < 2.0)
26
+ rspec-support (~> 3.1.0)
27
+ rspec-mocks (3.1.3)
28
+ rspec-support (~> 3.1.0)
29
+ rspec-support (3.1.2)
30
+ slop (3.6.0)
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ hashr
37
+ pry
38
+ rake
39
+ rb-brain!
40
+ rspec
@@ -0,0 +1,5 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task :default => :spec
@@ -1,4 +1,7 @@
1
1
  require 'brain/lookup'
2
+ require 'json'
3
+ require 'pry'
4
+ require 'hashr'
2
5
 
3
6
  module Brain
4
7
  class NeuralNetwork
@@ -187,6 +190,89 @@ module Brain
187
190
  data
188
191
  end
189
192
 
193
+ def to_json
194
+ # make json look like:
195
+ # {
196
+ # layers: [
197
+ # { x: {},
198
+ # y: {}},
199
+ # {'0': {bias: -0.98771313, weights: {x: 0.8374838, y: 1.245858},
200
+ # '1': {bias: 3.48192004, weights: {x: 1.7825821, y: -2.67899}}},
201
+ # { f: {bias: 0.27205739, weights: {'0': 1.3161821, '1': 2.00436}}}
202
+ # ]
203
+ # }
204
+ layers = []
205
+ (0..@output_layer).each do |layer|
206
+ layers[layer] = {}
207
+
208
+ if layer == 0 and @input_lookup
209
+ nodes = @input_lookup.keys
210
+ elsif layer == @output_layer and @output_lookup
211
+ nodes = @output_lookup.keys
212
+ else
213
+ nodes = (0...@sizes[layer]).to_a
214
+ end
215
+
216
+ (0...nodes.length).each do |j|
217
+ node = nodes[j]
218
+ layers[layer][node] = {}
219
+
220
+ if layer > 0
221
+ layers[layer][node][:bias] = @biases[layer][j]
222
+ layers[layer][node][:weights] = {}
223
+ layers[layer - 1].each do |k,v|
224
+ index = k
225
+ if layer == 1 and @input_lookup
226
+ index = @input_lookup[k]
227
+ end
228
+ layers[layer][node][:weights][k] = @weights[layer][j][index]
229
+ end
230
+ end
231
+ end
232
+ end
233
+
234
+ {
235
+ layers: layers,
236
+ output_lookup: !!@output_lookup,
237
+ input_lookup: !!@input_lookup
238
+ }.to_json
239
+ end
240
+
241
+ def from_json(json)
242
+ json = JSON.parse(json).deep_symbolize_keys
243
+ size = json[:layers].length
244
+
245
+
246
+ @output_layer = size - 1
247
+ @sizes = Array.new size
248
+ @weights = Array.new size
249
+ @biases = Array.new size
250
+ @outputs = Array.new size
251
+
252
+ (0..@output_layer).each do |i|
253
+ layer = json[:layers][i]
254
+ if i == 0 and (!layer[0] or json[:input_lookup])
255
+ @input_lookup = Lookup.lookup_from_hash layer
256
+ elsif i == @output_layer and (!layer[0] or json[:output_lookup])
257
+ @output_lookup = Lookup.lookup_from_hash layer
258
+ end
259
+
260
+ nodes = layer.keys
261
+ @sizes[i] = nodes.length
262
+ @weights[i] = []
263
+ @biases[i] = []
264
+ @outputs[i] = []
265
+
266
+ (0...nodes.length).each do |j|
267
+
268
+ node = nodes[j]
269
+ @biases[i][j] = layer[node][:bias]
270
+ @weights[i][j] = layer[node][:weights]
271
+ @weights[i][j] = @weights[i][j].values unless @weights[i][j].nil?
272
+ end
273
+ end
274
+ end
275
+
190
276
  private
191
277
  def random_weight
192
278
  Random.rand * 0.4 - 0.2
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |gem|
6
6
  gem.name = "rb-brain"
7
- gem.version = "0.0.1"
7
+ gem.version = "0.1.0"
8
8
  gem.authors = ["Eric Zhang"]
9
9
  gem.email = ["i@qinix.com"]
10
10
  gem.description = %q{rb-brain is an easy-to-use neural network written in ruby}
@@ -0,0 +1,31 @@
1
+ describe 'bitwase functions' do
2
+ it 'NOT function' do
3
+ data_not = [{input: [0], output: [1]},
4
+ {input: [1], output: [0]}]
5
+ test_bitwise data_not, 'not'
6
+ end
7
+
8
+ it 'XOR function' do
9
+ data_xor = [{input: [0, 0], output: [0]},
10
+ {input: [0, 1], output: [1]},
11
+ {input: [1, 0], output: [1]},
12
+ {input: [1, 1], output: [0]}]
13
+ test_bitwise data_xor, 'xor'
14
+ end
15
+
16
+ it 'OR function' do
17
+ data_or = [{input: [0, 0], output: [0]},
18
+ {input: [0, 1], output: [1]},
19
+ {input: [1, 0], output: [1]},
20
+ {input: [1, 1], output: [1]}]
21
+ test_bitwise data_or, 'or'
22
+ end
23
+
24
+ it 'AND function' do
25
+ data_and = [{input: [0, 0], output: [0]},
26
+ {input: [0, 1], output: [0]},
27
+ {input: [1, 0], output: [0]},
28
+ {input: [1, 1], output: [1]}]
29
+ test_bitwise data_and, 'and'
30
+ end
31
+ end
@@ -0,0 +1,70 @@
1
+ describe 'hash input and output' do
2
+ before :each do
3
+ @net = Brain::NeuralNetwork.new
4
+ end
5
+
6
+ it 'runs correctly with array input and output' do
7
+ @net.train([{input: { x: 0, y: 0 }, output: [0]},
8
+ {input: { x: 0, y: 1 }, output: [1]},
9
+ {input: { x: 1, y: 0 }, output: [1]},
10
+ {input: { x: 1, y: 1 }, output: [0]}])
11
+ output = @net.run({x: 1, y: 0})
12
+
13
+ expect(output[0]).to be > 0.9
14
+ end
15
+
16
+ it 'runs correctly with hash input' do
17
+ @net.train([{input: { x: 0, y: 0 }, output: [0]},
18
+ {input: { x: 0, y: 1 }, output: [1]},
19
+ {input: { x: 1, y: 0 }, output: [1]},
20
+ {input: { x: 1, y: 1 }, output: [0]}])
21
+ output = @net.run({x: 1, y: 0})
22
+
23
+ expect(output[0]).to be > 0.9
24
+ end
25
+
26
+ it 'runs correctly with hash output' do
27
+ @net.train([{input: [0, 0], output: { answer: 0 }},
28
+ {input: [0, 1], output: { answer: 1 }},
29
+ {input: [1, 0], output: { answer: 1 }},
30
+ {input: [1, 1], output: { answer: 0 }}])
31
+
32
+ output = @net.run([1, 0])
33
+
34
+ expect(output[:answer]).to be > 0.9
35
+ end
36
+
37
+ it 'runs correctly with hash input and output' do
38
+ @net.train([{input: { x: 0, y: 0 }, output: { answer: 0 }},
39
+ {input: { x: 0, y: 1 }, output: { answer: 1 }},
40
+ {input: { x: 1, y: 0 }, output: { answer: 1 }},
41
+ {input: { x: 1, y: 1 }, output: { answer: 0 }}])
42
+
43
+ output = @net.run({x: 1, y: 0})
44
+
45
+ expect(output[:answer]).to be > 0.9
46
+ end
47
+
48
+ it 'runs correctly with sparse hashes' do
49
+ @net.train([{input: {}, output: {}},
50
+ {input: { y: 1 }, output: { answer: 1 }},
51
+ {input: { x: 1 }, output: { answer: 1 }},
52
+ {input: { x: 1, y: 1 }, output: {}}])
53
+
54
+
55
+ output = @net.run({x: 1})
56
+
57
+ expect(output[:answer]).to be > 0.9
58
+ end
59
+
60
+ it 'runs correctly with unseen input' do
61
+ @net.train([{input: {}, output: {}},
62
+ {input: { y: 1 }, output: { answer: 1 }},
63
+ {input: { x: 1 }, output: { answer: 1 }},
64
+ {input: { x: 1, y: 1 }, output: {}}])
65
+
66
+ output = @net.run({x: 1, z: 1})
67
+
68
+ expect(output[:answer]).to be > 0.9
69
+ end
70
+ end
@@ -0,0 +1,21 @@
1
+ describe 'JSON' do
2
+ it 'to_json()/from_json()' do
3
+ net = Brain::NeuralNetwork.new
4
+
5
+ net.train([{input: {a: Random.rand, b: Random.rand},
6
+ output: {c: Random.rand, a: Random.rand}},
7
+ {input: {a: Random.rand, b: Random.rand},
8
+ output: {c: Random.rand, a: Random.rand}}])
9
+
10
+ json = net.to_json()
11
+ net2 = Brain::NeuralNetwork.new
12
+ net2.from_json json
13
+
14
+ input = {a: Random.rand, b: Random.rand}
15
+
16
+ output1 = net.run(input)
17
+ output2 = net2.run(input)
18
+
19
+ expect(output1).to eq output2
20
+ end
21
+ end
@@ -0,0 +1,32 @@
1
+ describe 'Lookup' do
2
+ it 'lookup_from_hash()' do
3
+ lup = Brain::Lookup.lookup_from_hash({ a: 6, b: 7, c: 8 })
4
+
5
+ expect(lup).to eq({ a: 0, b: 1, c: 2})
6
+ end
7
+
8
+ it 'build_lookup()' do
9
+ lup = Brain::Lookup.build_lookup([{ x: 0, y: 0 },
10
+ { x: 1, z: 0 },
11
+ { q: 0 },
12
+ { x: 1, y: 1 }])
13
+
14
+ expect(lup).to eq({ x: 0, y: 1, z: 2, q: 3 })
15
+ end
16
+
17
+ it 'to_array()' do
18
+ lup = { a: 0, b: 1, c: 2 }
19
+
20
+ array = Brain::Lookup.to_array(lup, { b: 8, notinlookup: 9 })
21
+
22
+ expect(array).to eq([0, 8, 0])
23
+ end
24
+
25
+ it 'to_hash()' do
26
+ lup = { b: 1, a: 0, c: 2 }
27
+
28
+ hash = Brain::Lookup.to_hash(lup, [0, 9, 8])
29
+
30
+ expect(hash).to eq({a: 0, b: 9, c: 8})
31
+ end
32
+ end
@@ -0,0 +1,83 @@
1
+ require 'json'
2
+ require 'hashr'
3
+
4
+ describe 'neural network options' do
5
+ it 'hiddenLayers' do
6
+ net = Brain::NeuralNetwork.new({ hidden_layers: [8, 7] })
7
+
8
+ net.train([{input: [0, 0], output: [0]},
9
+ {input: [0, 1], output: [1]},
10
+ {input: [1, 0], output: [1]},
11
+ {input: [1, 1], output: [0]}])
12
+
13
+ json = net.to_json
14
+ json = JSON.parse json
15
+ json.deep_symbolize_keys!
16
+
17
+ expect(json[:layers].length).to eq(4)
18
+ expect(json[:layers][1].length).to eq(8)
19
+ expect(json[:layers][2].length).to eq(7)
20
+ end
21
+
22
+ it 'hiddenLayers default expand to input size' do
23
+ net = Brain::NeuralNetwork.new()
24
+
25
+ net.train([{input: [0, 0, 1, 1, 1, 1, 1, 1, 1], output: [0]},
26
+ {input: [0, 1, 1, 1, 1, 1, 1, 1, 1], output: [1]},
27
+ {input: [1, 0, 1, 1, 1, 1, 1, 1, 1], output: [1]},
28
+ {input: [1, 1, 1, 1, 1, 1, 1, 1, 1], output: [0]}])
29
+
30
+ json = net.to_json
31
+ json = JSON.parse json
32
+ json.deep_symbolize_keys!
33
+
34
+ expect(json[:layers].length).to eq(3)
35
+ expect(json[:layers][1].length).to eq(4)
36
+ end
37
+
38
+
39
+ it 'learning_rate - higher learning rate should train faster' do
40
+ data = [{input: [0, 0], output: [0]},
41
+ {input: [0, 1], output: [1]},
42
+ {input: [1, 0], output: [1]},
43
+ {input: [1, 1], output: [1]}]
44
+
45
+ net1 = Brain::NeuralNetwork.new()
46
+ iters1 = net1.train(data, learning_rate: 0.5)[:iterations]
47
+
48
+ net2 = Brain::NeuralNetwork.new()
49
+ iters2 = net2.train(data, learning_rate: 0.8)[:iterations]
50
+
51
+ expect(iters1).to be > (iters2 * 1.1)
52
+ end
53
+
54
+ it 'learning_rate - backwards compatibility' do
55
+ data = [{input: [0, 0], output: [0]},
56
+ {input: [0, 1], output: [1]},
57
+ {input: [1, 0], output: [1]},
58
+ {input: [1, 1], output: [1]}]
59
+
60
+ net1 = Brain::NeuralNetwork.new(learning_rate: 0.5)
61
+ iters1 = net1.train(data)[:iterations]
62
+
63
+ net2 = Brain::NeuralNetwork.new(learning_rate: 0.8)
64
+ iters2 = net2.train(data)[:iterations]
65
+
66
+ expect(iters1).to be > (iters2 * 1.1)
67
+ end
68
+
69
+ it 'momentum - higher momentum should train faster' do
70
+ data = [{input: [0, 0], output: [0]},
71
+ {input: [0, 1], output: [1]},
72
+ {input: [1, 0], output: [1]},
73
+ {input: [1, 1], output: [1]}]
74
+
75
+ net1 = Brain::NeuralNetwork.new(momentum: 0.1)
76
+ iters1 = net1.train(data)[:iterations]
77
+
78
+ net2 = Brain::NeuralNetwork.new(momentum: 0.5)
79
+ iters2 = net2.train(data)[:iterations]
80
+
81
+ expect(iters1).to be > (iters2 * 1.1)
82
+ end
83
+ end
@@ -0,0 +1,26 @@
1
+ data = [{input: [0, 0], output: [0]},
2
+ {input: [0, 1], output: [1]},
3
+ {input: [1, 0], output: [1]},
4
+ {input: [1, 1], output: [1]}]
5
+
6
+ describe 'train() options' do
7
+ before :each do
8
+ @net = Brain::NeuralNetwork.new
9
+ end
10
+
11
+ it 'train until error threshold reached' do
12
+ error = @net.train(data,
13
+ errorThresh: 0.2,
14
+ iterations: 100000)[:error]
15
+
16
+ expect(error).to be < 0.2
17
+ end
18
+
19
+ it 'train until max iterations reached' do
20
+ stats = @net.train(data,
21
+ errorThresh: 0.001,
22
+ iterations: 1)
23
+
24
+ expect(stats[:iterations]).to eq(1)
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ require 'rspec'
2
+
3
+ Dir['spec/supports/**/*.rb'].each { |f| require File.expand_path(f) }
4
+
5
+ require 'brain'
6
+
7
+ RSpec.configure do |config|
8
+ config.include Helpers
9
+ end
10
+
@@ -0,0 +1,14 @@
1
+ module Helpers
2
+ def test_bitwise(data, op)
3
+ wiggle = 0.1
4
+
5
+ net = Brain::NeuralNetwork.new
6
+ net.train(data, error_thresh: 0.003)
7
+
8
+ data.each do |item|
9
+ output = net.run(item[:input])
10
+ target = item[:output]
11
+ expect(output[0]).to be_within(wiggle).of(target[0])
12
+ end
13
+ end
14
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rb-brain
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Zhang
@@ -17,13 +17,24 @@ executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
+ - ".rspec"
20
21
  - Gemfile
22
+ - Gemfile.lock
21
23
  - LICENSE
22
24
  - README.md
25
+ - Rakefile
23
26
  - lib/brain.rb
24
27
  - lib/brain/lookup.rb
25
28
  - lib/brain/neuralnetwork.rb
26
29
  - rb-brain.gemspec
30
+ - spec/lib/bitwise_spec.rb
31
+ - spec/lib/hash_spec.rb
32
+ - spec/lib/json_spec.rb
33
+ - spec/lib/lookup_spec.rb
34
+ - spec/lib/options_spec.rb
35
+ - spec/lib/trainopts_spec.rb
36
+ - spec/spec_helper.rb
37
+ - spec/supports/helpers.rb
27
38
  homepage: https://github.com/qinix/rb-brain
28
39
  licenses:
29
40
  - MIT
@@ -48,4 +59,12 @@ rubygems_version: 2.4.3
48
59
  signing_key:
49
60
  specification_version: 4
50
61
  summary: rb-brain is an easy-to-use neural network written in ruby
51
- test_files: []
62
+ test_files:
63
+ - spec/lib/bitwise_spec.rb
64
+ - spec/lib/hash_spec.rb
65
+ - spec/lib/json_spec.rb
66
+ - spec/lib/lookup_spec.rb
67
+ - spec/lib/options_spec.rb
68
+ - spec/lib/trainopts_spec.rb
69
+ - spec/spec_helper.rb
70
+ - spec/supports/helpers.rb