hopfield 1.2 → 1.3
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 +4 -4
- data/README.md +1 -1
- data/ext/hopfield/hopfield.c +55 -0
- data/lib/hopfield.rb +3 -3
- data/lib/hopfield/network.rb +35 -15
- data/lib/hopfield/training.rb +1 -3
- metadata +2 -17
- data/lib/hopfield/neuron.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb3940e29051c8015264955b03947a57aca274bf
|
4
|
+
data.tar.gz: 52ad2e0455663abb7d345391d31383bad489daf9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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.
|
data/ext/hopfield/hopfield.c
CHANGED
@@ -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
|
}
|
data/lib/hopfield.rb
CHANGED
@@ -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
|
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
|
data/lib/hopfield/network.rb
CHANGED
@@ -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]
|
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
|
-
|
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
|
-
|
55
|
+
i = self.random_pool[self.random_pool_index]
|
56
|
+
self.random_pool_index += 1
|
48
57
|
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
55
|
-
|
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 =
|
74
|
+
state = self.neurons
|
60
75
|
|
61
76
|
# Calculate the current error
|
62
|
-
|
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
|
-
:
|
73
|
-
:
|
74
|
-
:
|
92
|
+
did_change: change,
|
93
|
+
state: self.state,
|
94
|
+
error: self.last_error
|
75
95
|
}
|
76
96
|
end
|
77
97
|
|
data/lib/hopfield/training.rb
CHANGED
@@ -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) {
|
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.
|
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-
|
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
|