ruby_brain 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 243add4b6f64c99d4bc2de70f69ff74f8fe439fd
4
+ data.tar.gz: 979c86696fd11c0892031495e57e7f3746b8df2f
5
+ SHA512:
6
+ metadata.gz: a4d8118899133f660ebfb9a64dd1cd068bb7501dff0cf371b6a8937a51fb9d9c0949b45f76176e71404dc745aa766fd9d3853ef34b6015f1d9bc33025df00b48
7
+ data.tar.gz: e0aec12b42540e424555f50e3bd7784d136fd7d831ee01486967198461d2940d63f174cdcb4a6b7583bb0b5ffdd0aae8968879a45d137d03a07c02b725d13e49
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ *~
2
+ /.bundle/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.12.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ruby_brain.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 TODO: Write your name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # RubyBrain
2
+
3
+ RubyBrain is a library of neural net, deep learning for Ruby.
4
+ You can install/use this library easily because the core is created by using only Ruby standard library.
5
+
6
+ The code of RubyBrain is the neuron oriented style.
7
+ This means that a class which represents a neuraon exists and each neurons are instances of the class.
8
+ So, you can treat neurons flexibly in a network.
9
+ Instead, the speed is very slow and it might not be reasonable for applications to use this library in the core.
10
+ However this library may help you get more deep knowledge around neuralnet/deep learning.
11
+
12
+ ## Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ ```ruby
17
+ gem 'ruby_brain'
18
+ ```
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install ruby_brain
27
+
28
+ ## Usage
29
+
30
+ Please refer to
31
+ [github.com/elgoog/ruby_brain/README.org](https://github.com/elgoog/ruby_brain/blob/master/README.org)
32
+ for detail.
33
+
34
+ ## Development
35
+
36
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
37
+
38
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
39
+
40
+ ## Contributing
41
+
42
+ Bug reports and pull requests are welcome on GitHub at https://github.com/elgoog/ruby_brain.
43
+
44
+
45
+ ## License
46
+
47
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
48
+
data/README.org ADDED
@@ -0,0 +1,237 @@
1
+ * Introduction
2
+
3
+ RubyBrain is a library of neural net, deep learning for Ruby.
4
+ You can install/use this library easily because the core is created by using only Ruby standard library.
5
+
6
+ The code of RubyBrain is the neuron oriented style.
7
+ This means that a class which represents a neuraon exists and each neurons are instances of the class.
8
+ So, you can treat neurons flexibly in a network.
9
+ Instead, the speed is very slow and it might not be reasonable for applications to use this library in the core.
10
+ However this library may help you get more deep knowledge around neuralnet/deep learning.
11
+
12
+ * Installation
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ #+BEGIN_SRC ruby
17
+ gem 'ruby_brain'
18
+ #+END_SRC
19
+
20
+ And then execute:
21
+
22
+ #+BEGIN_SRC shell
23
+ $ bundle
24
+ #+END_SRC
25
+
26
+ Or install it yourself as:
27
+
28
+ #+BEGIN_SRC shell
29
+ $ gem install ruby_brain
30
+ #+END_SRC
31
+
32
+ * Usage
33
+
34
+ ** dataset
35
+
36
+ All dataset used for training/test/predicate must be 2 dimension array structure.
37
+ 1st dimension indicates samples and 2nd dimension is used for features.
38
+
39
+ *** example "AND"
40
+ Now we assume that we train a network to operate as "AND operator"
41
+ The true table of "AND operator" is as below.
42
+ In short, when both "in 1" and "in 2" are 1, the "out" should be 1
43
+ and 0 should be output for other input combinations.
44
+
45
+ | in 1 | in 2 | out |
46
+ |------+------+-----|
47
+ | 0 | 0 | 0 |
48
+ | 0 | 1 | 0 |
49
+ | 1 | 0 | 0 |
50
+ | 1 | 1 | 1 |
51
+
52
+ In this situation, you can prepare the dataset lake following Ruby array.
53
+ #+BEGIN_SRC ruby
54
+ training_input_set = [
55
+ [0, 0],
56
+ [0, 1],
57
+ [1, 0],
58
+ [1, 1],
59
+ ]
60
+
61
+ training_supervisor_set = [
62
+ [0],
63
+ [0],
64
+ [0],
65
+ [1],
66
+ ]
67
+ #+END_SRC
68
+
69
+ ** constructing a network
70
+
71
+ RubyBrain::Network class represents a network. The constructor accepts an array which specifies the network structure.
72
+ If we use 1 hidden layer which has 3 neurons for above "AND operator" example, following array indicates the structure.
73
+ #+BEGIN_SRC ruby
74
+ # 2 inputs
75
+ # 3 units in a hidden layer
76
+ # 1 output
77
+ [2, 3, 1]
78
+ #+END_SRC
79
+
80
+ You can use 2 hidden layers with following code.
81
+ #+BEGIN_SRC ruby
82
+ # 2 inputs
83
+ # 4 units in 1st hidden layer
84
+ # 3 units in 2nd hidden layer
85
+ # 1 output
86
+ [2, 4, 2, 1]
87
+ #+END_SRC
88
+
89
+ So, a netowrk is created by
90
+ #+BEGIN_SRC ruby
91
+ a_network = RubyBrain::Network.new([2, 3, 1])
92
+
93
+ # learning_rate can be set
94
+ a_network.learning_rate = 0.5
95
+
96
+ # the networks must be initialized before it is used
97
+ a_network.init_network
98
+ #+END_SRC
99
+
100
+ There are other options for the constructor.
101
+ Please refer to the code. Sorry for missing document.
102
+
103
+ ** training
104
+
105
+ An instance method =learn= is used for training the network.
106
+ You can specify not only dataset but also other options for training.
107
+ #+BEGIN_SRC ruby
108
+ # max_training_cout : max epoch
109
+ # tolerance : stop training if RMS error become smaller than this value.
110
+ a_network.learn(training_input_set, training_supervisor_set, max_training_count=100, tolerance=0.0004, monitoring_channels=[:best_params_training])
111
+ #+END_SRC
112
+
113
+ ** predicate
114
+
115
+ Use =get_forward_outputs= with input data for predicating something.
116
+ Input data should be 1 sample.
117
+ #+BEGIN_SRC ruby
118
+ a_network.get_forward_outputs([1, 0])
119
+ #+END_SRC
120
+
121
+ ** save weights to a file
122
+
123
+ You can save optimized weights into a file.
124
+ Weights are saved as YAML format.
125
+
126
+ #+BEGIN_SRC ruby
127
+ a_network.dump_weights_to_yaml('/path/to/saved/weights/file.yml')
128
+ #+END_SRC
129
+
130
+ ** restore weights from a file
131
+
132
+ Optimized weights can be saved into a YAML file and you can use it for initializing weights when you create a new network.
133
+ #+BEGIN_SRC ruby
134
+ a_network = RubyBrain::Network.new([2, 3, 1])
135
+ a_network.init_network
136
+ a_network.load_weights_from_yaml_file('/path/to/saved/weights/file.yml')
137
+ #+END_SRC
138
+
139
+ * Examples
140
+
141
+ ** MNIST
142
+ Following code is included in [[https://github.com/elgoog/ruby_brain/blob/master/examples/mnist.rb][examples/mnist.rb]]
143
+
144
+ This module dependos on [[https://rubygems.org/gems/mnist][mnist]] gem to load mnist data into ruby array.
145
+
146
+ #+BEGIN_SRC ruby
147
+ require 'ruby_brain'
148
+ require 'ruby_brain/dataset/mnist/data'
149
+ #+END_SRC
150
+
151
+ Get MNIST dataset from [[http://yann.lecun.com/exdb/mnist/][THE MNIST DATABASE of handwritten digits]] if the dataset files don't exist in the working directory.
152
+ And load them into Ruby array =dataset=.
153
+
154
+ #+BEGIN_SRC ruby
155
+ dataset = RubyBrain::DataSet::Mnist::data
156
+ #+END_SRC
157
+
158
+ Divide =dataset= into training and test data.
159
+ NUM_TRAIN_DATA means how many first images are used as training data.
160
+ We use first 5000 images for training here.
161
+
162
+ #+BEGIN_SRC ruby
163
+ NUM_TRAIN_DATA = 5000
164
+ training_input = dataset[:input][0..(NUM_TRAIN_DATA-1)]
165
+ training_supervisor = dataset[:output][0..(NUM_TRAIN_DATA-1)]
166
+ #+END_SRC
167
+
168
+ Then construct the network and initialize.
169
+ In this case, an image has 784(28x28) pixcels and 10 classes(0..9).
170
+ So, the network structure should be [784, 50, 10] with 1 hidden layer which has 50 units.
171
+ You can construct the structure with following code.
172
+
173
+ #+BEGIN_SRC ruby
174
+ # network structure [784, 50, 10]
175
+ network = RubyBrain::Network.new([dataset[:input].first.size, 50, dataset[:output].first.size])
176
+ # learning rate is 0.7
177
+ network.learning_rate = 0.7
178
+ # initialize network
179
+ network.init_network
180
+ #+END_SRC
181
+
182
+ Run training.
183
+ #+BEGIN_SRC ruby
184
+ network.learn(training_input, training_supervisor, max_training_count=100, tolerance=0.0004, monitoring_channels=[:best_params_training])
185
+ #+END_SRC
186
+
187
+ Now, An optimized network was completed.
188
+ You can check it.
189
+
190
+ First, add =argmax= function into Array class.
191
+ This method finds the index of the array position the max value exists.
192
+ We use this method for finding the class(label 0~9) whose probability is the highest.
193
+
194
+ #+BEGIN_SRC ruby
195
+ class Array
196
+ def argmax
197
+ max_i, max_val = 0, self.first
198
+ self.each_with_index do |v, i|
199
+ max_val, max_i = v, i if v > max_val
200
+ end
201
+ max_i
202
+ end
203
+ end
204
+ #+END_SRC
205
+
206
+ Then, you can review each classes(labels) predicated by the model with following code.
207
+
208
+ #+BEGIN_SRC ruby
209
+ results = []
210
+ test_input.each_with_index do |input, i|
211
+ input.each_with_index do |e, j|
212
+ print(e > 0.3 ? 'x' : ' ')
213
+ puts if (j % 28) == 0
214
+ end
215
+ puts
216
+ supervisor_label = test_supervisor[i].argmax
217
+ predicated_label = network.get_forward_outputs(test_input[i]).argmax
218
+ puts "test_supervisor: #{supervisor_label}"
219
+ puts "predicate: #{predicated_label}"
220
+ results << (supervisor_label == predicated_label)
221
+ puts "------------------------------------------------------------"
222
+ end
223
+
224
+ puts "accuracy: #{results.count(true).to_f/results.size}"
225
+ #+END_SRC
226
+
227
+ I tried to train wioth above conditions.
228
+ The accuracy of trained model was 92.3%.
229
+ The weights file is [[https://github.com/elgoog/weights_ruby_brain/blob/master/weights_782_50_10_1.yml][here]].
230
+
231
+ * Contributing
232
+
233
+ 1. Fork it ( https://github.com/elgoog/ruby_brain/fork )
234
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
235
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
236
+ 4. Push to the branch (`git push origin my-new-feature`)
237
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ruby_brain"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/examples/mnist.rb ADDED
@@ -0,0 +1,79 @@
1
+ require 'ruby_brain'
2
+ require 'ruby_brain/dataset/mnist/data'
3
+
4
+ # NUM_TEST_DATA = 50000
5
+
6
+ dataset = RubyBrain::DataSet::Mnist::data
7
+
8
+ NUM_TRAIN_DATA = 5000
9
+
10
+ training_input = dataset[:input][0..(NUM_TRAIN_DATA-1)]
11
+ training_supervisor = dataset[:output][0..(NUM_TRAIN_DATA-1)]
12
+
13
+ # test_input = dataset[:input][NUM_TRAIN_DATA..(NUM_TRAIN_DATA+NUM_TEST_DATA-1)]
14
+ # test_supervisor = dataset[:output][NUM_TRAIN_DATA..(NUM_TRAIN_DATA+NUM_TEST_DATA-1)]
15
+ test_input = dataset[:input][NUM_TRAIN_DATA..-1]
16
+ test_supervisor = dataset[:output][NUM_TRAIN_DATA..-1]
17
+
18
+ network = RubyBrain::Network.new([dataset[:input].first.size, 50, dataset[:output].first.size])
19
+ network.learning_rate = 0.7
20
+ network.init_network
21
+ ### You can load weights from file in this timing if you want.
22
+ # network.load_weights_from_yaml_file(File.dirname(__FILE__) + '/../best_weights_1469044985.yml')
23
+
24
+ ### You can initializes weights by loading weights from file if you want.
25
+ # network.load_weights_from_yaml_file('path/to/weights.yml.file')
26
+
27
+ network.learn(training_input, training_supervisor, max_training_count=100, tolerance=0.0004, monitoring_channels=[:best_params_training])
28
+
29
+ ### You can save weights into a yml file if you want.
30
+ # network.dump_weights_to_yaml('path/to/weights.yml.file')
31
+
32
+
33
+ class Array
34
+ def argmax
35
+ max_i, max_val = 0, self.first
36
+ self.each_with_index do |v, i|
37
+ max_val, max_i = v, i if v > max_val
38
+ end
39
+ max_i
40
+ end
41
+ end
42
+
43
+ results = []
44
+ test_input.each_with_index do |input, i|
45
+ ### You can see test input, label and predicated lable in standard out if you uncomment in this block
46
+ # input.each_with_index do |e, j|
47
+ # print(e > 0.3 ? 'x' : ' ')
48
+ # puts if (j % 28) == 0
49
+ # end
50
+ # puts
51
+ supervisor_label = test_supervisor[i].argmax
52
+ predicated_label = network.get_forward_outputs(test_input[i]).argmax
53
+ # puts "test_supervisor: #{supervisor_label}"
54
+ # puts "predicate: #{predicated_label}"
55
+ results << (supervisor_label == predicated_label)
56
+ # puts "------------------------------------------------------------"
57
+ end
58
+
59
+ puts "accuracy: #{results.count(true).to_f/results.size}"
60
+
61
+
62
+
63
+ ### you can do above procedure simply by using Trainer
64
+
65
+ # training_option = {
66
+ # learning_rate: 0.5,
67
+ # max_training_count: 50,
68
+ # tolerance: 0.0004,
69
+ # # initial_weights_file: 'weights_3_30_10_1429166740.yml',
70
+ # # initial_weights_file: 'best_weights_1429544001.yml',
71
+ # monitoring_channels: [:best_params_training]
72
+ # }
73
+
74
+ # RubyBrain::Trainer.normal_learning([dataset[:input].first.size, 50, dataset[:output].first.size],
75
+ # training_input, training_supervisor,
76
+ # training_option)
77
+
78
+
79
+