ai4r 1.6.1 → 1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,5 +24,6 @@ require "ai4r/classifiers/zero_r"
24
24
  require "ai4r/classifiers/hyperpipes"
25
25
  # Neural networks
26
26
  require "ai4r/neural_network/backpropagation"
27
+ require "ai4r/neural_network/hopfield"
27
28
  # Genetic Algorithms
28
29
  require "ai4r/genetic_algorithm/genetic_algorithm"
@@ -0,0 +1,149 @@
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
+ require File.dirname(__FILE__) + '/../data/parameterizable'
11
+
12
+ module Ai4r
13
+
14
+ module NeuralNetwork
15
+
16
+ # = Hopfield Net =
17
+ #
18
+ # A Hopfield Network is a recurrent Artificial Neural Network.
19
+ # Hopfield nets are able to memorize a set of patterns, and then evaluate
20
+ # an input, returning the most similar stored pattern (although
21
+ # convergence to one of the stored patterns is not guaranteed).
22
+ # Hopfield nets are great to deal with input noise. If a system accepts a
23
+ # discrete set of inputs, but inputs are subject to noise, you can use a
24
+ # Hopfield net to eliminate noise and identified the given input.
25
+ #
26
+ # = How to Use =
27
+ #
28
+ # data_set = Ai4r::Data::DataSet.new :data_items => array_of_patterns
29
+ # net = Ai4r::NeuralNetworks::Hopfield.new.train data_set
30
+ # net.eval input
31
+ # => one of the stored patterns in array_of_patterns
32
+ class Hopfield
33
+
34
+ include Ai4r::Data::Parameterizable
35
+
36
+ attr_reader :weights, :nodes
37
+
38
+ parameters_info :eval_iterations => "The network will run for a maximum "+
39
+ "of 'eval_iterations' iterations while evaluating an input. 500 by " +
40
+ "default.",
41
+ :active_node_value => "Default: 1",
42
+ :inactive_node_value => "Default: -1",
43
+ :threshold => "Default: 0"
44
+
45
+ def initialize
46
+ @eval_iterations = 500
47
+ @active_node_value = 1
48
+ @inactive_node_value = -1
49
+ @threshold = 0
50
+ end
51
+
52
+ # Prepares the network to memorize the given data set.
53
+ # Future calls to eval (should) return one of the memorized data items.
54
+ # A Hopfield network converges to a local minimum, but converge to one
55
+ # of the "memorized" patterns is not guaranteed.
56
+ def train(data_set)
57
+ @data_set = data_set
58
+ initialize_nodes(@data_set)
59
+ initialize_weights(@data_set)
60
+ return self
61
+ end
62
+
63
+ # You can use run instead of eval to propagate values step by step.
64
+ # With this you can verify the progress of the network output with
65
+ # each step.
66
+ #
67
+ # E.g.:
68
+ # pattern = input
69
+ # 100.times do
70
+ # pattern = net.run(pattern)
71
+ # puts pattern.inspect
72
+ # end
73
+ def run(input)
74
+ set_input(input)
75
+ propagate
76
+ return @nodes
77
+ end
78
+
79
+ # Propagates the input until the network returns one of the memorized
80
+ # patterns, or a maximum of "eval_iterations" times.
81
+ def eval(input)
82
+ set_input(input)
83
+ @eval_iterations.times do
84
+ propagate
85
+ break if @data_set.data_items.include?(@nodes)
86
+ end
87
+ return @nodes
88
+ end
89
+
90
+ protected
91
+ # Set all nodes state to the given input.
92
+ # inputs parameter must have the same dimension as nodes
93
+ def set_input(inputs)
94
+ raise ArgumentError unless inputs.length == @nodes.length
95
+ inputs.each_with_index { |input, i| @nodes[i] = input}
96
+ end
97
+
98
+ # Select a single node randomly and propagate its state to all other nodes
99
+ def propagate
100
+ sum = 0
101
+ i = (rand * @nodes.length).floor
102
+ @nodes.each_with_index {|node, j| sum += read_weight(i,j)*node }
103
+ @nodes[i] = (sum > @threshold) ? @active_node_value : @inactive_node_value
104
+ end
105
+
106
+ # Initialize all nodes with "inactive" state.
107
+ def initialize_nodes(data_set)
108
+ @nodes = Array.new(data_set.data_items.first.length,
109
+ @inactive_node_value)
110
+ end
111
+
112
+ # Create a partial weigth matrix:
113
+ # [
114
+ # [w(1,0)],
115
+ # [w(2,0)], [w(2,1)],
116
+ # [w(3,0)], [w(3,1)], [w(3,2)],
117
+ # ...
118
+ # [w(n-1,0)], [w(n-1,1)], [w(n-1,2)], ... , [w(n-1,n-2)]
119
+ # ]
120
+ # where n is the number of nodes.
121
+ #
122
+ # We are saving memory here, as:
123
+ #
124
+ # * w[i][i] = 0 (no node connects with itself)
125
+ # * w[i][j] = w[j][i] (weigths are symmetric)
126
+ #
127
+ # Use read_weight(i,j) to find out weight between node i and j
128
+ def initialize_weights(data_set)
129
+ @weights = Array.new(@nodes.length-1) {|l| Array.new(l+1)}
130
+ @nodes.each_index do |i|
131
+ i.times do |j|
132
+ @weights[i-1][j] = data_set.data_items.inject(0) { |sum, item| sum+= item[i]*item[j] }
133
+ end
134
+ end
135
+ end
136
+
137
+ # read_weight(i,j) reads the weigth matrix and returns weight between
138
+ # node i and j
139
+ def read_weight(index_a, index_b)
140
+ return 0 if index_a == index_b
141
+ index_a, index_b = index_b, index_a if index_b > index_a
142
+ return @weights[index_a-1][index_b]
143
+ end
144
+
145
+ end
146
+
147
+ end
148
+
149
+ end
@@ -0,0 +1,72 @@
1
+ # This is a unit test file for the hopfield neural network AI4r implementation
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__) + '/../../lib/ai4r'
13
+ require 'test/unit'
14
+
15
+ Ai4r::NeuralNetwork::Hopfield.send(:public, *Ai4r::NeuralNetwork::Hopfield.protected_instance_methods)
16
+
17
+ module Ai4r
18
+
19
+ module NeuralNetwork
20
+
21
+
22
+ class HopfieldTest < Test::Unit::TestCase
23
+
24
+ def setup
25
+ @data_set = Ai4r::Data::DataSet.new :data_items => [
26
+ [1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1],
27
+ [-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1],
28
+ [-1,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,1,1,1,1],
29
+ [1,1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,-1,-1],
30
+ ]
31
+ end
32
+
33
+ def test_initialize_nodes
34
+ net = Hopfield.new
35
+ data_set = Ai4r::Data::DataSet.new :data_items => [[1,1,0,0,1,1,0,0]]
36
+ assert_equal [-1,-1,-1,-1,-1,-1,-1,-1], net.initialize_nodes(data_set)
37
+ end
38
+
39
+ def test_initialize_weights
40
+ net = Hopfield.new
41
+ net.initialize_nodes @data_set
42
+ net.initialize_weights(@data_set)
43
+ assert_equal 15, net.weights.length
44
+ net.weights.each_with_index {|w_row, i| assert_equal i+1, w_row.length}
45
+ end
46
+
47
+ def test_run
48
+ net = Hopfield.new
49
+ net.train @data_set
50
+ pattern = [1,1,-1,1,1,1,-1,-1,1,1,-1,-1,1,1,1,-1]
51
+ 100.times do
52
+ pattern = net.run(pattern)
53
+ end
54
+ assert_equal [1,1,-1,-1,1,1,-1,-1,1,1,-1,-1,1,1,-1,-1], pattern
55
+ end
56
+
57
+ def test_eval
58
+ net = Hopfield.new
59
+ net.train @data_set
60
+ p = [1,1,-1,1,1,1,-1,-1,1,1,-1,-1,1,1,1,-1]
61
+ assert_equal @data_set.data_items[0], net.eval(p)
62
+ p = [-1,-1,1,1,1,-1,1,1,-1,-1,1,-1,-1,-1,1,1]
63
+ assert_equal @data_set.data_items[1], net.eval(p)
64
+ p = [-1,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,1,1,-1,-1]
65
+ assert_equal @data_set.data_items[2], net.eval(p)
66
+ p = [-1,-1,1,1,1,1,1,1,-1,-1,-1,-1,1,-1,-1,-1]
67
+ assert_equal @data_set.data_items[3], net.eval(p)
68
+ end
69
+
70
+ end
71
+ end
72
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ai4r
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.1
4
+ version: "1.7"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergio Fierens
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-09 00:00:00 +01:00
12
+ date: 2009-04-29 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -55,6 +55,7 @@ files:
55
55
  - lib/ai4r/experiment/classifier_evaluator.rb
56
56
  - lib/ai4r/neural_network
57
57
  - lib/ai4r/neural_network/backpropagation.rb
58
+ - lib/ai4r/neural_network/hopfield.rb
58
59
  - lib/ai4r/classifiers
59
60
  - lib/ai4r/classifiers/hyperpipes.rb
60
61
  - lib/ai4r/classifiers/multilayer_perceptron.rb
@@ -109,6 +110,7 @@ test_files:
109
110
  - test/clusterers/k_means_test.rb
110
111
  - test/clusterers/bisecting_k_means_test.rb
111
112
  - test/experiment/classifier_evaluator_test.rb
113
+ - test/neural_network/hopfield_test.rb
112
114
  - test/neural_network/backpropagation_test.rb
113
115
  - test/classifiers/zero_r_test.rb
114
116
  - test/classifiers/multilayer_perceptron_test.rb