hopfield 1.2 → 1.3

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: 6f1e7bbc674b32b5f95647dcb42109ce6a37bc0b
4
- data.tar.gz: 083b4ff167702baf75a0dd050e3fd75de42f1c97
3
+ metadata.gz: eb3940e29051c8015264955b03947a57aca274bf
4
+ data.tar.gz: 52ad2e0455663abb7d345391d31383bad489daf9
5
5
  SHA512:
6
- metadata.gz: 110a161f19c05846bde6fa84d4775af490ec44c7c3352b71338ca4c436ce793ac3b27b09e410fc70b85b1337c33c15f59fd9eefd85c339b9a99c57032d1aebd3
7
- data.tar.gz: 56c9fb943f7be0e5d23983c5db41e8739b1c10118252828bfa9a21f40af5d42cf69aa59ae1437d28bd70e426b2bbb1e2aa7224dc7d51470345f46544a4d47759
6
+ metadata.gz: 0bf65127ea952843e26c0089e7f1e0eae112b336382b5e106726779f09d723312905e19d0add3971f6ce5e751c132302a5062e904dc645baa6e4ebb554a30aab
7
+ data.tar.gz: 8eaa5500db84c1891bded3e90035697782c6e610655a9ebad241d04af136f6e61ed9b14fec4fa961afcc15c1332486973241a89a02f299cd79bf569870b756bc
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Hopfield Network in Ruby
2
2
 
3
- A pure, albeit slow Ruby implementation of a Hopfield Network.
3
+ A short and simple Ruby implementation of a Hopfield Network. Includes a small C extension to speed up the CPU intensive loops.
4
4
 
5
5
  ## What is it?
6
6
  [Hopfield Networks](http://en.wikipedia.org/wiki/Hopfield_network) model the way humans recall memories, or more specific, how neurons recall the pattern. This means you first train the network with a set of known patterns and then pass an unknown or perturbed version of the pattern. The neurons will restore the missing information to create an exact match.
@@ -38,10 +38,65 @@ static VALUE hopfield_calculate_weights_hebbian(VALUE self, VALUE patterns, VALU
38
38
  return weights;
39
39
  }
40
40
 
41
+ static VALUE hopfield_transfer_activation(float activation) {
42
+ return INT2FIX((activation >= 0) ? 1 : -1);
43
+ }
44
+
45
+ static VALUE hopfield_calculate_neuron_state(VALUE self, VALUE neuron_index, VALUE neurons, VALUE weights) {
46
+ Check_Type(neuron_index, T_FIXNUM);
47
+ Check_Type(neurons, T_ARRAY);
48
+ Check_Type(weights, T_ARRAY);
49
+
50
+ float activation = 0.0;
51
+ int i = FIX2INT(neuron_index);
52
+ int neurons_count = (int) RARRAY_LEN(neurons);
53
+
54
+ for(int j = 0; j < neurons_count; j++) {
55
+ if (j == i)
56
+ continue;
57
+
58
+ int w_i = (i < j) ? i : j;
59
+ int w_j = (j > i) ? j : i;
60
+
61
+ activation += NUM2DBL(rb_ary_entry(rb_ary_entry(weights, w_i), w_j)) * NUM2DBL(rb_ary_entry(neurons, j));
62
+ }
63
+
64
+ return hopfield_transfer_activation(activation);
65
+ }
66
+
67
+ static VALUE hopfield_calculate_state_errors(VALUE self, VALUE state, VALUE patterns) {
68
+ Check_Type(state, T_ARRAY);
69
+ Check_Type(patterns, T_ARRAY);
70
+
71
+ // Compare state to patterns and calculate errors for each pattern
72
+ int patterns_count = (int) RARRAY_LEN(patterns);
73
+ int pattern_length = (int) RARRAY_LEN(state);
74
+
75
+ VALUE errors = rb_ary_new2(patterns_count);
76
+
77
+ for(int p = 0; p < patterns_count; p++) {
78
+ int sum = 0;
79
+
80
+ for(int c = 0; c < pattern_length; c++) {
81
+ int state_value = FIX2INT(rb_ary_entry(state, c));
82
+ int pattern_value = FIX2INT(rb_ary_entry(rb_ary_entry(patterns, p), c));
83
+ if (pattern_value != state_value)
84
+ sum++;
85
+ }
86
+
87
+ rb_ary_push(errors, INT2FIX(sum));
88
+ }
89
+
90
+ return errors;
91
+ }
92
+
41
93
  /* ruby calls this to load the extension */
42
94
  void Init_hopfield(void) {
43
95
 
44
96
  m_hopfield = rb_define_module("Hopfield");
45
97
 
46
98
  rb_define_module_function(m_hopfield, "calculate_weights_hebbian", hopfield_calculate_weights_hebbian, 2);
99
+ rb_define_module_function(m_hopfield, "calculate_neuron_state", hopfield_calculate_neuron_state, 3);
100
+
101
+ rb_define_module_function(m_hopfield, "calculate_state_errors", hopfield_calculate_state_errors, 2);
47
102
  }
@@ -1,12 +1,12 @@
1
1
  require 'hopfield/hopfield'
2
2
 
3
- require_relative 'hopfield/neuron'
4
3
  require_relative 'hopfield/training'
5
4
  require_relative 'hopfield/network'
6
5
 
7
6
  module Hopfield
8
- # Hopfield consists of three parts:
9
- # => Neuron (hopfield/neuron.rb)
7
+ # Hopfield consists of two parts:
10
8
  # => Training (hopfield/training.rb)
11
9
  # => Network (hopfield/network.rb)
10
+
11
+ USE_C_EXTENSION = true
12
12
  end
@@ -1,6 +1,6 @@
1
1
  module Hopfield
2
2
  class Network
3
- attr_accessor :neurons, :patterns, :weights, :state, :pattern_dimensions, :last_error, :runs
3
+ attr_accessor :neurons, :patterns, :weights, :state, :pattern_dimensions, :last_error, :runs, :random_pool, :random_pool_index
4
4
 
5
5
  def initialize(training, perturbed_pattern)
6
6
  unless training.class.to_s == 'Hopfield::Training'
@@ -20,9 +20,14 @@ module Hopfield
20
20
  self.pattern_dimensions = training.pattern_dimensions
21
21
 
22
22
  self.neurons.count.times do |i|
23
- self.neurons[i].state = perturbed_pattern[i]
23
+ self.neurons[i] = perturbed_pattern[i]
24
24
  end
25
25
 
26
+ # Create a semi random pool to improve performance
27
+ # This prevents propagation of the same neuron over and over again
28
+ self.random_pool = (0...self.neurons.count).to_a.shuffle
29
+ self.random_pool_index = rand(self.neurons.count)
30
+
26
31
  self.last_error = [1]
27
32
  self.runs = 0
28
33
  end
@@ -42,24 +47,39 @@ module Hopfield
42
47
 
43
48
  def propagate
44
49
  # Select random neuron
45
- i = rand(self.neurons.count)
50
+ if self.random_pool_index == self.random_pool.size - 1
51
+ self.random_pool_index = 0
52
+ self.random_pool.shuffle!
53
+ end
46
54
 
47
- activation = 0.0
55
+ i = self.random_pool[self.random_pool_index]
56
+ self.random_pool_index += 1
48
57
 
49
- self.neurons.each_with_index do |other, j|
50
- next if i == j
51
- activation += get_weight(i, j)*other.state
58
+ if USE_C_EXTENSION
59
+ output = Hopfield::calculate_neuron_state(i, self.neurons, self.weights)
60
+ else
61
+ # Ruby equivalent of calculate_neuron_state C function
62
+ activation = 0.0
63
+ self.neurons.each_with_index do |other, j|
64
+ next if i == j
65
+ activation += get_weight(i, j)*other
66
+ end
67
+ output = transfer(activation)
52
68
  end
53
69
 
54
- output = transfer(activation)
55
- change = output != self.neurons[i].state
56
- self.neurons[i].state = output
70
+ change = output != self.neurons[i]
71
+ self.neurons[i] = output
57
72
 
58
73
  # Compile state of outputs
59
- state = Array.new(self.neurons.count){ |i| self.neurons[i].state }
74
+ state = self.neurons
60
75
 
61
76
  # Calculate the current error
62
- self.last_error = calculate_error(state)
77
+ if USE_C_EXTENSION
78
+ self.last_error = Hopfield::calculate_state_errors(state, self.patterns)
79
+ else
80
+ # Ruby equivalent of calcuting the current error
81
+ self.last_error = calculate_error(state)
82
+ end
63
83
 
64
84
  # Convert state to binary and back to a multi dimensional array
65
85
  state = to_binary(state)
@@ -69,9 +89,9 @@ module Hopfield
69
89
  self.runs += 1
70
90
 
71
91
  return {
72
- :did_change => change,
73
- :state => self.state,
74
- :error => self.last_error
92
+ did_change: change,
93
+ state: self.state,
94
+ error: self.last_error
75
95
  }
76
96
  end
77
97
 
@@ -5,8 +5,6 @@ module Hopfield
5
5
  HEBBIAN_RULE = 1
6
6
  STORKEY_RULE = 2
7
7
 
8
- USE_C_EXTENSION = true
9
-
10
8
  class Training
11
9
  attr_accessor :patterns, :neurons, :weights, :pattern_dimensions, :rule
12
10
 
@@ -31,7 +29,7 @@ module Hopfield
31
29
  self.patterns = self.patterns.map { |pattern| pattern.map { |value| (value == 0 ? -1 : value) }}
32
30
 
33
31
  # Create neurons
34
- self.neurons = Array.new(self.patterns.first.length) { Neuron.new }
32
+ self.neurons = Array.new(self.patterns.first.length) { 0.0 }
35
33
 
36
34
  self.weights = Array.new
37
35
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hopfield
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.2'
4
+ version: '1.3'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bart Olsthoorn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-03 00:00:00.000000000 Z
11
+ date: 2013-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: chunky_png
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - '>='
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - '>='
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
27
  description: Hopfield networks can be used for smart pattern recollections. It's recalling
42
28
  patterns by modelling associative memory of a neural network
43
29
  email:
@@ -48,7 +34,6 @@ extensions:
48
34
  extra_rdoc_files: []
49
35
  files:
50
36
  - lib/hopfield/network.rb
51
- - lib/hopfield/neuron.rb
52
37
  - lib/hopfield/training.rb
53
38
  - lib/hopfield.rb
54
39
  - ext/hopfield/hopfield.c
@@ -1,5 +0,0 @@
1
- module Hopfield
2
- class Neuron
3
- attr_accessor :state
4
- end
5
- end