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 +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +48 -0
- data/README.org +237 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/mnist.rb +79 -0
- data/examples/mnist2.rb +82 -0
- data/lib/ruby_brain.rb +19 -0
- data/lib/ruby_brain/dataset/mnist/data.rb +62 -0
- data/lib/ruby_brain/dataset/mnist/test_mnist.rb +28 -0
- data/lib/ruby_brain/exception.rb +17 -0
- data/lib/ruby_brain/layer.rb +37 -0
- data/lib/ruby_brain/network.rb +252 -0
- data/lib/ruby_brain/nodes.rb +58 -0
- data/lib/ruby_brain/trainer.rb +71 -0
- data/lib/ruby_brain/training_data_manipulator.rb +35 -0
- data/lib/ruby_brain/version.rb +3 -0
- data/lib/ruby_brain/weights.rb +82 -0
- data/ruby_brain.gemspec +34 -0
- metadata +125 -0
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
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
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
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
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
|
+
|