reddavis-mlp 0.0.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.
- data/.autotest +1 -0
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +46 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/examples/backpropagation_example.rb +73 -0
- data/examples/patterns_with_base_noise.rb +68 -0
- data/examples/patterns_with_noise.rb +66 -0
- data/examples/training_patterns.rb +68 -0
- data/examples/xor.rb +28 -0
- data/lib/mlp.rb +123 -0
- data/lib/neuron.rb +51 -0
- data/mlp.gemspec +64 -0
- data/test/helper.rb +10 -0
- data/test/test_mlp.rb +77 -0
- data/test/test_neuron.rb +16 -0
- metadata +78 -0
data/.autotest
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'redgreen/autotest'
|
data/.document
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2009 reddavis
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
= Multi-Layer Perceptron Neural Network
|
|
2
|
+
|
|
3
|
+
I built this to not only learn about the MLP but to also make a very simple, well laid out MLP so other can easily see what's happening.
|
|
4
|
+
|
|
5
|
+
I also suggest checking out http://bit.ly/XEWOc for a great tutorial.
|
|
6
|
+
|
|
7
|
+
== Install
|
|
8
|
+
|
|
9
|
+
gem sources -a http://gems.github.com
|
|
10
|
+
sudo gem install reddavis-mlp
|
|
11
|
+
|
|
12
|
+
== How To Use
|
|
13
|
+
require 'rubygems'
|
|
14
|
+
require 'mlp'
|
|
15
|
+
|
|
16
|
+
a = MLP.new(:hidden_layers => [2], :output_nodes => 1, :inputs => 2)
|
|
17
|
+
|
|
18
|
+
3001.times do |i|
|
|
19
|
+
a.train([0,0], [0])
|
|
20
|
+
a.train([0,1], [1])
|
|
21
|
+
a.train([1,0], [1])
|
|
22
|
+
error = a.train([1,1], [0])
|
|
23
|
+
puts "Error after iteration #{i}:\t#{error}" if i%200 == 0
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
puts "Test data"
|
|
27
|
+
puts "[0,0] = > #{a.feed_forward([0,0]).inspect}"
|
|
28
|
+
puts "[0,1] = > #{a.feed_forward([0,1]).inspect}"
|
|
29
|
+
puts "[1,0] = > #{a.feed_forward([1,0]).inspect}"
|
|
30
|
+
puts "[1,1] = > #{a.feed_forward([1,1]).inspect}"
|
|
31
|
+
|
|
32
|
+
== Benchmarks
|
|
33
|
+
|
|
34
|
+
The above example produces these times
|
|
35
|
+
|
|
36
|
+
user system total real
|
|
37
|
+
MLP 0.820000 0.000000 0.820000 ( 0.837693)
|
|
38
|
+
Ai4R 1.180000 0.010000 1.190000 ( 1.232388)
|
|
39
|
+
|
|
40
|
+
== Thanks
|
|
41
|
+
|
|
42
|
+
* David Richards - For his code reviews and all round helpfulness. - http://github.com/davidrichards
|
|
43
|
+
|
|
44
|
+
== Copyright
|
|
45
|
+
|
|
46
|
+
Copyright (c) 2009 Red Davis. See LICENSE for details.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rake'
|
|
3
|
+
|
|
4
|
+
begin
|
|
5
|
+
require 'jeweler'
|
|
6
|
+
Jeweler::Tasks.new do |gem|
|
|
7
|
+
gem.name = "mlp"
|
|
8
|
+
gem.summary = %Q{Multi-Layer Perceptron Neural Network in Ruby}
|
|
9
|
+
gem.description = %Q{Multi-Layer Perceptron Neural Network in Ruby}
|
|
10
|
+
gem.email = "reddavis@gmail.com"
|
|
11
|
+
gem.homepage = "http://github.com/reddavis/mlp"
|
|
12
|
+
gem.authors = ["reddavis"]
|
|
13
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
rescue LoadError
|
|
17
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
require 'rake/testtask'
|
|
21
|
+
Rake::TestTask.new(:test) do |test|
|
|
22
|
+
test.libs << 'lib' << 'test'
|
|
23
|
+
test.pattern = 'test/**/*_test.rb'
|
|
24
|
+
test.verbose = true
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
begin
|
|
28
|
+
require 'rcov/rcovtask'
|
|
29
|
+
Rcov::RcovTask.new do |test|
|
|
30
|
+
test.libs << 'test'
|
|
31
|
+
test.pattern = 'test/**/*_test.rb'
|
|
32
|
+
test.verbose = true
|
|
33
|
+
end
|
|
34
|
+
rescue LoadError
|
|
35
|
+
task :rcov do
|
|
36
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
task :default => :test
|
|
44
|
+
|
|
45
|
+
require 'rake/rdoctask'
|
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
|
47
|
+
if File.exist?('VERSION')
|
|
48
|
+
version = File.read('VERSION')
|
|
49
|
+
else
|
|
50
|
+
version = ""
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
54
|
+
rdoc.title = "mlp #{version}"
|
|
55
|
+
rdoc.rdoc_files.include('README*')
|
|
56
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
57
|
+
end
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.0.0
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# This test was taken from ai4r gem
|
|
2
|
+
|
|
3
|
+
# Author:: Sergio Fierens
|
|
4
|
+
# License:: MPL 1.1
|
|
5
|
+
# Project:: ai4r
|
|
6
|
+
# Url:: http://ai4r.rubyforge.org/
|
|
7
|
+
#
|
|
8
|
+
# You can redistribute it and/or modify it under the terms of
|
|
9
|
+
# the Mozilla Public License version 1.1 as published by the
|
|
10
|
+
# Mozilla Foundation at http://www.mozilla.org/MPL/MPL-1.1.txt
|
|
11
|
+
|
|
12
|
+
require File.dirname(__FILE__) + '/training_patterns'
|
|
13
|
+
require File.dirname(__FILE__) + '/patterns_with_noise'
|
|
14
|
+
require File.dirname(__FILE__) + '/patterns_with_base_noise'
|
|
15
|
+
require File.dirname(__FILE__) + '/../lib/mlp'
|
|
16
|
+
require 'benchmark'
|
|
17
|
+
|
|
18
|
+
times = Benchmark.measure do
|
|
19
|
+
|
|
20
|
+
srand 1
|
|
21
|
+
|
|
22
|
+
net = MLP.new(:hidden_layers => [2], :output_nodes => 3, :inputs => 256)
|
|
23
|
+
|
|
24
|
+
tr_with_noise = TRIANGLE_WITH_NOISE.flatten.collect { |input| input.to_f / 5.0}
|
|
25
|
+
sq_with_noise = SQUARE_WITH_NOISE.flatten.collect { |input| input.to_f / 5.0}
|
|
26
|
+
cr_with_noise = CROSS_WITH_NOISE.flatten.collect { |input| input.to_f / 5.0}
|
|
27
|
+
|
|
28
|
+
tr_with_base_noise = TRIANGLE_WITH_BASE_NOISE.flatten.collect { |input| input.to_f / 5.0}
|
|
29
|
+
sq_with_base_noise = SQUARE_WITH_BASE_NOISE.flatten.collect { |input| input.to_f / 5.0}
|
|
30
|
+
cr_with_base_noise = CROSS_WITH_BASE_NOISE.flatten.collect { |input| input.to_f / 5.0}
|
|
31
|
+
|
|
32
|
+
puts "Training the network, please wait."
|
|
33
|
+
101.times do |i|
|
|
34
|
+
tr_input = TRIANGLE.flatten.collect { |input| input.to_f / 5.0}
|
|
35
|
+
sq_input = SQUARE.flatten.collect { |input| input.to_f / 5.0}
|
|
36
|
+
cr_input = CROSS.flatten.collect { |input| input.to_f / 5.0}
|
|
37
|
+
|
|
38
|
+
error1 = net.train(tr_input, [1,0,0])
|
|
39
|
+
error2 = net.train(sq_input, [0,1,0])
|
|
40
|
+
error3 = net.train(cr_input, [0,0,1])
|
|
41
|
+
puts "Error after iteration #{i}:\t#{error1} - #{error2} - #{error3}" if i%20 == 0
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def result_label(result)
|
|
45
|
+
if result[0] > result[1] && result[0] > result[2]
|
|
46
|
+
"TRIANGLE"
|
|
47
|
+
elsif result[1] > result[2]
|
|
48
|
+
"SQUARE"
|
|
49
|
+
else
|
|
50
|
+
"CROSS"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
tr_input = TRIANGLE.flatten.collect { |input| input.to_f / 5.0}
|
|
55
|
+
sq_input = SQUARE.flatten.collect { |input| input.to_f / 5.0}
|
|
56
|
+
cr_input = CROSS.flatten.collect { |input| input.to_f / 5.0}
|
|
57
|
+
|
|
58
|
+
puts "Training Examples"
|
|
59
|
+
puts "#{net.feed_forward(tr_input).inspect} => #{result_label(net.feed_forward(tr_input))}"
|
|
60
|
+
puts "#{net.feed_forward(sq_input).inspect} => #{result_label(net.feed_forward(sq_input))}"
|
|
61
|
+
puts "#{net.feed_forward(cr_input).inspect} => #{result_label(net.feed_forward(cr_input))}"
|
|
62
|
+
puts "Examples with noise"
|
|
63
|
+
puts "#{net.feed_forward(tr_with_noise).inspect} => #{result_label(net.feed_forward(tr_with_noise))}"
|
|
64
|
+
puts "#{net.feed_forward(sq_with_noise).inspect} => #{result_label(net.feed_forward(sq_with_noise))}"
|
|
65
|
+
puts "#{net.feed_forward(cr_with_noise).inspect} => #{result_label(net.feed_forward(cr_with_noise))}"
|
|
66
|
+
puts "Examples with base noise"
|
|
67
|
+
puts "#{net.feed_forward(tr_with_base_noise).inspect} => #{result_label(net.feed_forward(tr_with_base_noise))}"
|
|
68
|
+
puts "#{net.feed_forward(sq_with_base_noise).inspect} => #{result_label(net.feed_forward(sq_with_base_noise))}"
|
|
69
|
+
puts "#{net.feed_forward(cr_with_base_noise).inspect} => #{result_label(net.feed_forward(cr_with_base_noise))}"
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
puts "Elapsed time: #{times}"
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Author:: Sergio Fierens
|
|
2
|
+
# License:: MPL 1.1
|
|
3
|
+
# Project:: ai4r
|
|
4
|
+
# Url:: http://ai4r.rubyforge.org/
|
|
5
|
+
#
|
|
6
|
+
# You can redistribute it and/or modify it under the terms of
|
|
7
|
+
# the Mozilla Public License version 1.1 as published by the
|
|
8
|
+
# Mozilla Foundation at http://www.mozilla.org/MPL/MPL-1.1.txt
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
TRIANGLE_WITH_BASE_NOISE = [
|
|
12
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3],
|
|
13
|
+
[ 3, 3, 3, 3, 3, 3, 4, 10, 10, 4, 3, 3, 3, 3, 3, 3],
|
|
14
|
+
[ 3, 3, 3, 3, 3, 3, 8, 8, 8, 8, 3, 3, 3, 3, 3, 3],
|
|
15
|
+
[ 3, 3, 3, 3, 3, 4, 10, 4, 4, 10, 4, 3, 3, 3, 3, 3],
|
|
16
|
+
[ 3, 3, 3, 3, 3, 8, 8, 3, 3, 8, 8, 3, 3, 3, 3, 3],
|
|
17
|
+
[ 3, 3, 3, 3, 4, 10, 4, 3, 3, 4, 10, 4, 3, 3, 3, 3],
|
|
18
|
+
[ 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3],
|
|
19
|
+
[ 3, 3, 3, 4, 10, 4, 3, 3, 3, 3, 4, 10, 4, 3, 3, 3],
|
|
20
|
+
[ 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3],
|
|
21
|
+
[ 3, 3, 4, 10, 4, 3, 3, 3, 3, 3, 3, 4, 10, 4, 3, 3],
|
|
22
|
+
[ 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3],
|
|
23
|
+
[ 3, 4, 10, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 10, 4, 3],
|
|
24
|
+
[ 3, 8, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 8, 8, 3],
|
|
25
|
+
[ 4, 10, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 10, 4],
|
|
26
|
+
[ 8, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 8, 8],
|
|
27
|
+
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
SQUARE_WITH_BASE_NOISE = [
|
|
31
|
+
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10],
|
|
32
|
+
[10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10],
|
|
33
|
+
[10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10],
|
|
34
|
+
[10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10],
|
|
35
|
+
[10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10],
|
|
36
|
+
[10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10],
|
|
37
|
+
[10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10],
|
|
38
|
+
[10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10],
|
|
39
|
+
[10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10],
|
|
40
|
+
[10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10],
|
|
41
|
+
[10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10],
|
|
42
|
+
[10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10],
|
|
43
|
+
[10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10],
|
|
44
|
+
[10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10],
|
|
45
|
+
[10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10],
|
|
46
|
+
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
|
|
47
|
+
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
CROSS_WITH_BASE_NOISE = [
|
|
51
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3],
|
|
52
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3],
|
|
53
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3],
|
|
54
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3],
|
|
55
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3],
|
|
56
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3],
|
|
57
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3],
|
|
58
|
+
[ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8],
|
|
59
|
+
[ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8],
|
|
60
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3],
|
|
61
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3],
|
|
62
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3],
|
|
63
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3],
|
|
64
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3],
|
|
65
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3],
|
|
66
|
+
[ 3, 3, 3, 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3]
|
|
67
|
+
]
|
|
68
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Author:: Sergio Fierens
|
|
2
|
+
# License:: MPL 1.1
|
|
3
|
+
# Project:: ai4r
|
|
4
|
+
# Url:: http://ai4r.rubyforge.org/
|
|
5
|
+
#
|
|
6
|
+
# You can redistribute it and/or modify it under the terms of
|
|
7
|
+
# the Mozilla Public License version 1.1 as published by the
|
|
8
|
+
# Mozilla Foundation at http://www.mozilla.org/MPL/MPL-1.1.txt
|
|
9
|
+
|
|
10
|
+
TRIANGLE_WITH_NOISE = [
|
|
11
|
+
[ 1, 0, 0, 0, 0, 0, 0, 1, 5, 0, 0, 1, 0, 0, 0, 0],
|
|
12
|
+
[ 0, 0, 0, 0, 3, 0, 1, 9, 9, 1, 0, 0, 0, 0, 3, 0],
|
|
13
|
+
[ 0, 3, 0, 0, 0, 0, 5, 1, 5, 3, 0, 0, 0, 0, 0, 7],
|
|
14
|
+
[ 0, 0, 0, 7, 0, 1, 9, 1, 1, 9, 1, 0, 0, 0, 3, 0],
|
|
15
|
+
[ 0, 0, 0, 0, 0, 3, 5, 0, 3, 5, 5, 0, 0, 0, 0, 0],
|
|
16
|
+
[ 0, 1, 0, 0, 1, 9, 1, 0, 1, 1, 9, 1, 0, 0, 0, 0],
|
|
17
|
+
[ 1, 0, 0, 0, 5, 5, 0, 0, 0, 0, 5, 5, 7, 0, 0, 3],
|
|
18
|
+
[ 0, 0, 3, 3, 9, 1, 0, 0, 1, 0, 1, 9, 1, 0, 0, 0],
|
|
19
|
+
[ 0, 0, 0, 5, 5, 0, 3, 7, 0, 0, 0, 5, 5, 0, 0, 0],
|
|
20
|
+
[ 0, 0, 1, 9, 1, 0, 0, 0, 0, 0, 0, 1, 9, 1, 0, 0],
|
|
21
|
+
[ 0, 0, 5, 5, 0, 0, 0, 0, 3, 0, 0, 0, 5, 5, 0, 0],
|
|
22
|
+
[ 0, 1, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9, 1, 0],
|
|
23
|
+
[ 0, 5, 5, 0, 3, 0, 0, 3, 0, 0, 0, 0, 0, 5, 5, 0],
|
|
24
|
+
[ 1, 9, 1, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 9, 1],
|
|
25
|
+
[ 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5],
|
|
26
|
+
[10, 10, 10, 10, 1, 10, 10, 10, 10, 10, 1, 10, 10, 10, 10, 10]
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
SQUARE_WITH_NOISE = [
|
|
30
|
+
[10, 3, 10, 10, 10, 6, 10, 10, 10, 10, 10, 4, 10, 10, 10, 10],
|
|
31
|
+
[10, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
32
|
+
[10, 0, 3, 0, 0, 0, 0, 7, 0, 6, 1, 0, 0, 0, 0, 0],
|
|
33
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
34
|
+
[10, 0, 4, 0, 4, 0, 0, 0, 1, 0, 3, 0, 0, 4, 0, 10],
|
|
35
|
+
[10, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
|
|
36
|
+
[10, 0, 0, 0, 3, 6, 0, 0, 1, 0, 0, 0, 0, 0, 0, 10],
|
|
37
|
+
[10, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 7, 0, 0, 10],
|
|
38
|
+
[10, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
39
|
+
[10, 0, 7, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
40
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 7, 10],
|
|
41
|
+
[10, 0, 3, 0, 4, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 10],
|
|
42
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 10],
|
|
43
|
+
[10, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 10],
|
|
44
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
45
|
+
[10, 10, 10, 10, 3, 10, 10, 10, 10, 0, 10, 10, 1, 10, 1, 10]
|
|
46
|
+
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
CROSS_WITH_NOISE = [
|
|
50
|
+
[ 0, 0, 0, 0, 0, 0, 3, 3, 5, 0, 3, 0, 0, 0, 1, 0],
|
|
51
|
+
[ 0, 1, 0, 0, 0, 1, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
52
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 3, 0, 0, 0],
|
|
53
|
+
[ 0, 0, 1, 8, 0, 0, 0, 5, 5, 0, 4, 0, 0, 0, 1, 0],
|
|
54
|
+
[ 0, 0, 0, 0, 0, 3, 0, 5, 0, 0, 0, 0, 1, 0, 0, 0],
|
|
55
|
+
[ 0, 0, 0, 8, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 1],
|
|
56
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 3, 0, 0, 0, 0, 0],
|
|
57
|
+
[ 5, 5, 5, 8, 5, 3, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5],
|
|
58
|
+
[ 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 5, 5, 1, 0, 0],
|
|
59
|
+
[ 0, 0, 0, 8, 0, 0, 0, 4, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
60
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 4, 0, 0, 0, 0, 0, 0],
|
|
61
|
+
[ 0, 0, 0, 0, 0, 4, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
62
|
+
[ 4, 0, 0, 4, 0, 0, 0, 5, 5, 0, 0, 0, 1, 0, 0, 0],
|
|
63
|
+
[ 0, 0, 0, 0, 0, 1, 0, 5, 4, 4, 3, 0, 0, 0, 0, 0],
|
|
64
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 10, 0, 0, 0],
|
|
65
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0]
|
|
66
|
+
]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Author:: Sergio Fierens
|
|
2
|
+
# License:: MPL 1.1
|
|
3
|
+
# Project:: ai4r
|
|
4
|
+
# Url:: http://ai4r.rubyforge.org/
|
|
5
|
+
#
|
|
6
|
+
# You can redistribute it and/or modify it under the terms of
|
|
7
|
+
# the Mozilla Public License version 1.1 as published by the
|
|
8
|
+
# Mozilla Foundation at http://www.mozilla.org/MPL/MPL-1.1.txt
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
TRIANGLE = [
|
|
12
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
13
|
+
[ 0, 0, 0, 0, 0, 0, 1, 9, 9, 1, 0, 0, 0, 0, 0, 0],
|
|
14
|
+
[ 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0],
|
|
15
|
+
[ 0, 0, 0, 0, 0, 1, 9, 1, 1, 9, 1, 0, 0, 0, 0, 0],
|
|
16
|
+
[ 0, 0, 0, 0, 0, 5, 5, 0, 0, 5, 5, 0, 0, 0, 0, 0],
|
|
17
|
+
[ 0, 0, 0, 0, 1, 9, 1, 0, 0, 1, 9, 1, 0, 0, 0, 0],
|
|
18
|
+
[ 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0],
|
|
19
|
+
[ 0, 0, 0, 1, 9, 1, 0, 0, 0, 0, 1, 9, 1, 0, 0, 0],
|
|
20
|
+
[ 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0],
|
|
21
|
+
[ 0, 0, 1, 9, 1, 0, 0, 0, 0, 0, 0, 1, 9, 1, 0, 0],
|
|
22
|
+
[ 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0],
|
|
23
|
+
[ 0, 1, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9, 1, 0],
|
|
24
|
+
[ 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0],
|
|
25
|
+
[ 1, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9, 1],
|
|
26
|
+
[ 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5],
|
|
27
|
+
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
SQUARE = [
|
|
31
|
+
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10],
|
|
32
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
33
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
34
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
35
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
36
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
37
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
38
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
39
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
40
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
41
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
42
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
43
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
44
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
45
|
+
[10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10],
|
|
46
|
+
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
|
|
47
|
+
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
CROSS = [
|
|
51
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
52
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
53
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
54
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
55
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
56
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
57
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
58
|
+
[ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5],
|
|
59
|
+
[ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5],
|
|
60
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
61
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
62
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
63
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
64
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
65
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
66
|
+
[ 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0]
|
|
67
|
+
]
|
|
68
|
+
|
data/examples/xor.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# This test was taken from ai4r gem
|
|
2
|
+
|
|
3
|
+
require File.dirname(__FILE__) + '/../lib/mlp'
|
|
4
|
+
require 'benchmark'
|
|
5
|
+
|
|
6
|
+
times = Benchmark.measure do
|
|
7
|
+
|
|
8
|
+
srand 1
|
|
9
|
+
|
|
10
|
+
a = MLP.new(:hidden_layers => [2], :output_nodes => 1, :inputs => 2)
|
|
11
|
+
|
|
12
|
+
3001.times do |i|
|
|
13
|
+
a.train([0,0], [0])
|
|
14
|
+
a.train([0,1], [1])
|
|
15
|
+
a.train([1,0], [1])
|
|
16
|
+
error = a.train([1,1], [0])
|
|
17
|
+
puts "Error after iteration #{i}:\t#{error}" if i%200 == 0
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
puts "Test data"
|
|
21
|
+
puts "[0,0] = > #{a.feed_forward([0,0]).inspect}"
|
|
22
|
+
puts "[0,1] = > #{a.feed_forward([0,1]).inspect}"
|
|
23
|
+
puts "[1,0] = > #{a.feed_forward([1,0]).inspect}"
|
|
24
|
+
puts "[1,1] = > #{a.feed_forward([1,1]).inspect}"
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
puts "Elapsed time: #{times}"
|
data/lib/mlp.rb
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/neuron'
|
|
2
|
+
|
|
3
|
+
class MLP
|
|
4
|
+
|
|
5
|
+
def initialize(options={})
|
|
6
|
+
@input_size = options[:inputs]
|
|
7
|
+
@hidden_layers = options[:hidden_layers]
|
|
8
|
+
@number_of_output_nodes = options[:output_nodes]
|
|
9
|
+
setup_network
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def feed_forward(input)
|
|
13
|
+
@network.each_with_index do |layer, layer_index|
|
|
14
|
+
layer.each do |neuron|
|
|
15
|
+
if layer_index == 0
|
|
16
|
+
neuron.fire(input)
|
|
17
|
+
else
|
|
18
|
+
input = @network[layer_index-1].map {|x| x.last_output}
|
|
19
|
+
neuron.fire(input)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
@network.last.map {|x| x.last_output}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def train(input, targets)
|
|
27
|
+
# To go back we must go forward
|
|
28
|
+
feed_forward(input)
|
|
29
|
+
compute_deltas(targets)
|
|
30
|
+
update_weights(input)
|
|
31
|
+
calculate_error(targets)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def inspect
|
|
35
|
+
@network
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def update_weights(input)
|
|
41
|
+
reversed_network = @network.reverse
|
|
42
|
+
reversed_network.each_with_index do |layer, layer_index|
|
|
43
|
+
if layer_index == 0
|
|
44
|
+
update_output_weights(layer, layer_index, input)
|
|
45
|
+
else
|
|
46
|
+
update_hidden_weights(layer, layer_index, input)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def update_output_weights(layer, layer_index, input)
|
|
52
|
+
inputs = @hidden_layers.empty? ? input : @network[-2].map {|x| x.last_output}
|
|
53
|
+
layer.each do |neuron|
|
|
54
|
+
neuron.update_weight(inputs, 0.25)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def update_hidden_weights(layer, layer_index, original_input)
|
|
59
|
+
if layer_index == (@network.size - 1)
|
|
60
|
+
inputs = original_input
|
|
61
|
+
else
|
|
62
|
+
inputs = @network.reverse[layer_index+1].map {|x| x.last_output}
|
|
63
|
+
end
|
|
64
|
+
layer.each do |neuron|
|
|
65
|
+
neuron.update_weight(inputs, 0.25)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def compute_deltas(targets)
|
|
70
|
+
reversed_network = @network.reverse
|
|
71
|
+
reversed_network.each_with_index do |layer, layer_index|
|
|
72
|
+
if layer_index == 0
|
|
73
|
+
compute_output_deltas(layer, targets)
|
|
74
|
+
else
|
|
75
|
+
compute_hidden_deltas(layer, targets)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def compute_output_deltas(layer, targets)
|
|
81
|
+
layer.each_with_index do |neuron, i|
|
|
82
|
+
output = neuron.last_output
|
|
83
|
+
neuron.delta = output * (1 - output) * (targets[i] - output)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def compute_hidden_deltas(layer, targets)
|
|
88
|
+
layer.each_with_index do |neuron, neuron_index|
|
|
89
|
+
error = 0
|
|
90
|
+
@network.last.each do |output_neuron|
|
|
91
|
+
error += output_neuron.delta * output_neuron.weights[neuron_index]
|
|
92
|
+
end
|
|
93
|
+
output = neuron.last_output
|
|
94
|
+
neuron.delta = output * (1 - output) * error
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def calculate_error(targets)
|
|
99
|
+
outputs = @network.last.map {|x| x.last_output}
|
|
100
|
+
sum = 0
|
|
101
|
+
targets.each_with_index do |t, index|
|
|
102
|
+
sum += (t - outputs[index]) ** 2
|
|
103
|
+
end
|
|
104
|
+
0.5 * sum
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def setup_network
|
|
108
|
+
@network = []
|
|
109
|
+
# Hidden Layers
|
|
110
|
+
@hidden_layers.each_with_index do |number_of_neurons, index|
|
|
111
|
+
layer = []
|
|
112
|
+
inputs = index == 0 ? @input_size : @hidden_layers[index-1].size
|
|
113
|
+
number_of_neurons.times { layer << Neuron.new(inputs) }
|
|
114
|
+
@network << layer
|
|
115
|
+
end
|
|
116
|
+
# Output layer
|
|
117
|
+
inputs = @hidden_layers.empty? ? @input_size : @hidden_layers.last
|
|
118
|
+
layer = []
|
|
119
|
+
@number_of_output_nodes.times { layer << Neuron.new(inputs)}
|
|
120
|
+
@network << layer
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
end
|
data/lib/neuron.rb
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
class Neuron
|
|
2
|
+
|
|
3
|
+
attr_reader :last_output, :weights
|
|
4
|
+
attr_accessor :delta
|
|
5
|
+
|
|
6
|
+
def initialize(number_of_inputs)
|
|
7
|
+
create_weights(number_of_inputs)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def fire(input)
|
|
11
|
+
@last_output = activation_function(input)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def update_weight(inputs, training_rate)
|
|
15
|
+
inputs << -1 # Add the bias
|
|
16
|
+
@weights.each_index do |i|
|
|
17
|
+
@weights[i] += training_rate * delta * inputs[i]
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def inspect
|
|
22
|
+
@weights
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def activation_function(input)
|
|
28
|
+
sum = 0
|
|
29
|
+
input.each_with_index do |n, index|
|
|
30
|
+
# puts "index:#{index} weight: #{@weights[index]} input: #{n} input_size: #{input.size}"
|
|
31
|
+
sum += @weights[index] * n
|
|
32
|
+
end
|
|
33
|
+
sum += @weights.last * -1 #bias node
|
|
34
|
+
sigmoid_function(sum)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# g(h) = 1 / (1+exp(-B*h(j)))
|
|
38
|
+
def sigmoid_function(x)
|
|
39
|
+
1 / (1+Math.exp(-1 * (x)))
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def create_weights(number_of_inputs)
|
|
43
|
+
# Create random weights between 0 & 1
|
|
44
|
+
# Plus another one for the bias node
|
|
45
|
+
@weights = []
|
|
46
|
+
(number_of_inputs + 1).times do
|
|
47
|
+
@weights << (rand > 0.5 ? -rand : rand)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
data/mlp.gemspec
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Generated by jeweler
|
|
2
|
+
# DO NOT EDIT THIS FILE
|
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
|
4
|
+
# -*- encoding: utf-8 -*-
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |s|
|
|
7
|
+
s.name = %q{mlp}
|
|
8
|
+
s.version = "0.0.0"
|
|
9
|
+
|
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
|
+
s.authors = ["reddavis"]
|
|
12
|
+
s.date = %q{2009-09-02}
|
|
13
|
+
s.description = %q{Multi-Layer Perceptron Neural Network in Ruby}
|
|
14
|
+
s.email = %q{reddavis@gmail.com}
|
|
15
|
+
s.extra_rdoc_files = [
|
|
16
|
+
"LICENSE",
|
|
17
|
+
"README.rdoc"
|
|
18
|
+
]
|
|
19
|
+
s.files = [
|
|
20
|
+
".autotest",
|
|
21
|
+
".document",
|
|
22
|
+
".gitignore",
|
|
23
|
+
"LICENSE",
|
|
24
|
+
"README.rdoc",
|
|
25
|
+
"Rakefile",
|
|
26
|
+
"VERSION",
|
|
27
|
+
"examples/backpropagation_example.rb",
|
|
28
|
+
"examples/patterns_with_base_noise.rb",
|
|
29
|
+
"examples/patterns_with_noise.rb",
|
|
30
|
+
"examples/training_patterns.rb",
|
|
31
|
+
"examples/xor.rb",
|
|
32
|
+
"lib/mlp.rb",
|
|
33
|
+
"lib/neuron.rb",
|
|
34
|
+
"mlp.gemspec",
|
|
35
|
+
"test/helper.rb",
|
|
36
|
+
"test/test_mlp.rb",
|
|
37
|
+
"test/test_neuron.rb"
|
|
38
|
+
]
|
|
39
|
+
s.homepage = %q{http://github.com/reddavis/mlp}
|
|
40
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
|
41
|
+
s.require_paths = ["lib"]
|
|
42
|
+
s.rubygems_version = %q{1.3.5}
|
|
43
|
+
s.summary = %q{Multi-Layer Perceptron Neural Network in Ruby}
|
|
44
|
+
s.test_files = [
|
|
45
|
+
"test/helper.rb",
|
|
46
|
+
"test/test_mlp.rb",
|
|
47
|
+
"test/test_neuron.rb",
|
|
48
|
+
"examples/backpropagation_example.rb",
|
|
49
|
+
"examples/patterns_with_base_noise.rb",
|
|
50
|
+
"examples/patterns_with_noise.rb",
|
|
51
|
+
"examples/training_patterns.rb",
|
|
52
|
+
"examples/xor.rb"
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
if s.respond_to? :specification_version then
|
|
56
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
57
|
+
s.specification_version = 3
|
|
58
|
+
|
|
59
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
|
60
|
+
else
|
|
61
|
+
end
|
|
62
|
+
else
|
|
63
|
+
end
|
|
64
|
+
end
|
data/test/helper.rb
ADDED
data/test/test_mlp.rb
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
require 'helper'
|
|
2
|
+
|
|
3
|
+
class TestMLP < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
should "contain 4 layers" do
|
|
6
|
+
a = MLP.new(:hidden_layers => [2, 2, 2], :output_nodes => 2, :inputs => 2)
|
|
7
|
+
assert_equal 4, a.inspect.size
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
should "create an output neuron with 3 weights" do
|
|
11
|
+
a = MLP.new(:hidden_layers => [2], :output_nodes => 1, :inputs => 2)
|
|
12
|
+
assert_equal 3, a.inspect.last.last.weights.size
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
should "create a hidden neuron with 3 weights" do
|
|
16
|
+
a = MLP.new(:hidden_layers => [2], :output_nodes => 1, :inputs => 2)
|
|
17
|
+
assert_equal 3, a.inspect.first.last.weights.size
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
should "feed forward and set all neurons last outputs" do
|
|
21
|
+
a = MLP.new(:hidden_layers => [2], :output_nodes => 2, :inputs => 2)
|
|
22
|
+
a.feed_forward([0,1])
|
|
23
|
+
b = a.inspect.inject([]) do |array, n|
|
|
24
|
+
array << n.map {|x| x.last_output}
|
|
25
|
+
end
|
|
26
|
+
b.flatten!
|
|
27
|
+
assert !b.include?(nil)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
should "return an array after feed forward" do
|
|
31
|
+
a = MLP.new(:hidden_layers => [2], :output_nodes => 2, :inputs => 2)
|
|
32
|
+
assert_kind_of Array, a.feed_forward([0,1])
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
should "set its neurons deltas" do
|
|
36
|
+
a = MLP.new(:hidden_layers => [2], :output_nodes => 1, :inputs => 2)
|
|
37
|
+
a.train([0,1], [0])
|
|
38
|
+
b = a.inspect.inject([]) do |array, n|
|
|
39
|
+
array << n.map {|x| x.delta}
|
|
40
|
+
end
|
|
41
|
+
b.flatten!
|
|
42
|
+
assert !b.include?(nil)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
should "update its output neurons weights" do
|
|
46
|
+
a = MLP.new(:hidden_layers => [2], :output_nodes => 1, :inputs => 2)
|
|
47
|
+
before = a.inspect.last.first.weights.inject([]) do |array, n|
|
|
48
|
+
array << n
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
a.train([0,1], [0])
|
|
52
|
+
after = a.inspect.last.first.weights.inject([]) do |array, n|
|
|
53
|
+
array << n
|
|
54
|
+
end
|
|
55
|
+
assert_not_equal before, after
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
should "update its hidden neurons weights" do
|
|
59
|
+
a = MLP.new(:hidden_layers => [2], :output_nodes => 1, :inputs => 2)
|
|
60
|
+
before = a.inspect.first.first.weights.inject([]) do |array, n|
|
|
61
|
+
array << n
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
a.train([0,1], [0])
|
|
65
|
+
after = a.inspect.first.first.weights.inject([]) do |array, n|
|
|
66
|
+
array << n
|
|
67
|
+
end
|
|
68
|
+
assert_not_equal before, after
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
should "return the error (float) after training" do
|
|
72
|
+
a = MLP.new(:hidden_layers => [2], :output_nodes => 1, :inputs => 2)
|
|
73
|
+
error = a.train([0,1], [0])
|
|
74
|
+
assert_kind_of Float, error
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
end
|
data/test/test_neuron.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'helper'
|
|
2
|
+
|
|
3
|
+
class TestNeuron < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
should "contain 3 weights (including weight for bias node)" do
|
|
6
|
+
a = Neuron.new(2)
|
|
7
|
+
assert_equal 3, a.inspect.size
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
should "save its last output" do
|
|
11
|
+
a = Neuron.new(2)
|
|
12
|
+
a.fire([0,1])
|
|
13
|
+
assert a.last_output
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: reddavis-mlp
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- reddavis
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2009-09-02 00:00:00 -07:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies: []
|
|
15
|
+
|
|
16
|
+
description: Multi-Layer Perceptron Neural Network in Ruby
|
|
17
|
+
email: reddavis@gmail.com
|
|
18
|
+
executables: []
|
|
19
|
+
|
|
20
|
+
extensions: []
|
|
21
|
+
|
|
22
|
+
extra_rdoc_files:
|
|
23
|
+
- LICENSE
|
|
24
|
+
- README.rdoc
|
|
25
|
+
files:
|
|
26
|
+
- .autotest
|
|
27
|
+
- .document
|
|
28
|
+
- .gitignore
|
|
29
|
+
- LICENSE
|
|
30
|
+
- README.rdoc
|
|
31
|
+
- Rakefile
|
|
32
|
+
- VERSION
|
|
33
|
+
- examples/backpropagation_example.rb
|
|
34
|
+
- examples/patterns_with_base_noise.rb
|
|
35
|
+
- examples/patterns_with_noise.rb
|
|
36
|
+
- examples/training_patterns.rb
|
|
37
|
+
- examples/xor.rb
|
|
38
|
+
- lib/mlp.rb
|
|
39
|
+
- lib/neuron.rb
|
|
40
|
+
- mlp.gemspec
|
|
41
|
+
- test/helper.rb
|
|
42
|
+
- test/test_mlp.rb
|
|
43
|
+
- test/test_neuron.rb
|
|
44
|
+
has_rdoc: false
|
|
45
|
+
homepage: http://github.com/reddavis/mlp
|
|
46
|
+
post_install_message:
|
|
47
|
+
rdoc_options:
|
|
48
|
+
- --charset=UTF-8
|
|
49
|
+
require_paths:
|
|
50
|
+
- lib
|
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: "0"
|
|
56
|
+
version:
|
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: "0"
|
|
62
|
+
version:
|
|
63
|
+
requirements: []
|
|
64
|
+
|
|
65
|
+
rubyforge_project:
|
|
66
|
+
rubygems_version: 1.2.0
|
|
67
|
+
signing_key:
|
|
68
|
+
specification_version: 3
|
|
69
|
+
summary: Multi-Layer Perceptron Neural Network in Ruby
|
|
70
|
+
test_files:
|
|
71
|
+
- test/helper.rb
|
|
72
|
+
- test/test_mlp.rb
|
|
73
|
+
- test/test_neuron.rb
|
|
74
|
+
- examples/backpropagation_example.rb
|
|
75
|
+
- examples/patterns_with_base_noise.rb
|
|
76
|
+
- examples/patterns_with_noise.rb
|
|
77
|
+
- examples/training_patterns.rb
|
|
78
|
+
- examples/xor.rb
|