SimpleNeuralNetwork 0.0.1
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/lib/layer.rb +71 -0
- data/lib/network.rb +78 -0
- data/lib/neuron.rb +28 -0
- data/lib/simple_neural_network.rb +3 -0
- metadata +47 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 46f5556f65b4606a5e8314e7ba7791f73ba314fd
|
4
|
+
data.tar.gz: 72fdae81f4c25de9f57bf4295f064d414dcd5380
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7149124f6817e608bba4ad2f9ca8419bbf50c27991fc1565b59f0f42cb8b2d1bdfa17fb4ad3bfeb4c41055eb19b7bec0b22e30361ead91c4c3251c4fb9a2c92a
|
7
|
+
data.tar.gz: 73e138bd6e0b474fcf57e576a884a407fe6512f2e0ae66ed8ab8ae2c22143247ac6b24aae5c2c409d3e19a83d3ea41075d71745b96c2ed34f9d5b5a31b4f9d35
|
data/lib/layer.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require_relative "neuron"
|
2
|
+
|
3
|
+
class SimpleNeuralNetwork
|
4
|
+
class Layer
|
5
|
+
# Number of neurons
|
6
|
+
attr_accessor :size
|
7
|
+
|
8
|
+
attr_accessor :prev_layer
|
9
|
+
attr_accessor :next_layer
|
10
|
+
|
11
|
+
# List of #{size} neurons
|
12
|
+
attr_accessor :neurons
|
13
|
+
|
14
|
+
attr_accessor :network
|
15
|
+
|
16
|
+
def initialize(size, network)
|
17
|
+
@size = size
|
18
|
+
@neurons = []
|
19
|
+
@network = network
|
20
|
+
|
21
|
+
populate_neurons
|
22
|
+
end
|
23
|
+
|
24
|
+
# The method that drives network output resolution.
|
25
|
+
# get_output calculates the array of node values for this layer.
|
26
|
+
# This is calculated by recursively fetching the output from the previous layer, then applying edge/node weight rules.
|
27
|
+
# The first layer will fetch it's values from @network.inputs
|
28
|
+
def get_output
|
29
|
+
if !prev_layer
|
30
|
+
# This is the first layer, so the output set is simply the network input set
|
31
|
+
@network.inputs
|
32
|
+
else
|
33
|
+
# Each neuron output value is calculated by:
|
34
|
+
# output[i] = (
|
35
|
+
# (prev_layer.neurons[0] * prev_layer.neurons[0].edges[i])
|
36
|
+
# + (prev_layer.neurons[1] * prev_layer.neurons[1].edges[i])
|
37
|
+
# + ...
|
38
|
+
# ) + self.neurons[i].bias
|
39
|
+
|
40
|
+
prev_layer_output = prev_layer.get_output
|
41
|
+
|
42
|
+
# Generate the output values for the layer
|
43
|
+
(0..@size-1).map do |i|
|
44
|
+
value = 0
|
45
|
+
|
46
|
+
prev_layer_output.each_with_index do |output, index|
|
47
|
+
value += (output * prev_layer.neurons[index].edges[i])
|
48
|
+
end
|
49
|
+
|
50
|
+
value + @neurons[i].bias
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize_neuron_edges
|
56
|
+
return unless @next_layer
|
57
|
+
|
58
|
+
@neurons.each do |neuron|
|
59
|
+
neuron.initialize_edges(@next_layer.size)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def populate_neurons
|
66
|
+
@size.times do
|
67
|
+
@neurons << Neuron.new(layer: self)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/network.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require_relative "layer"
|
2
|
+
|
3
|
+
# To properly initialze a network:
|
4
|
+
# - Initialize the new Network object
|
5
|
+
# - Create layers using Network#create_layer
|
6
|
+
# (This creates layers from left to right, input -> hidden layers -> output layer)
|
7
|
+
# - Call Network#initialize_edges to populate neuron edges in the network.
|
8
|
+
# This has to be done after creating all layers because the number of edges depends
|
9
|
+
# on the number on neurons in the next layer
|
10
|
+
class SimpleNeuralNetwork
|
11
|
+
class Network
|
12
|
+
class InvalidInputError < StandardError; end
|
13
|
+
# An array of layers
|
14
|
+
attr_accessor :layers
|
15
|
+
|
16
|
+
attr_accessor :inputs
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@layers = []
|
20
|
+
@inputs = []
|
21
|
+
end
|
22
|
+
|
23
|
+
# Run an input set against the neural network.
|
24
|
+
# Accepts an array of input integers between 0 and 1 of length #input_size
|
25
|
+
# Returns
|
26
|
+
def run(inputs)
|
27
|
+
unless inputs.size == input_size && inputs.all? { |input| input >= 0 && input <= 1 }
|
28
|
+
raise InvalidInputError.new("Invalid input passed to Network#run")
|
29
|
+
end
|
30
|
+
|
31
|
+
@inputs = inputs
|
32
|
+
|
33
|
+
# Get output from last layer. It recursively depends on layers before it.
|
34
|
+
@layers[-1].get_output
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the number of input nodes
|
38
|
+
def input_size
|
39
|
+
@layers[0].size
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the number of output nodes
|
43
|
+
def output_size
|
44
|
+
@layers[-1].size
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_layer(neurons:)
|
48
|
+
unless @layers.empty?
|
49
|
+
new_layer = Layer.new(neurons, self)
|
50
|
+
prev_layer = @layers.last
|
51
|
+
|
52
|
+
@layers << new_layer
|
53
|
+
|
54
|
+
new_layer.prev_layer = prev_layer
|
55
|
+
prev_layer.next_layer = new_layer
|
56
|
+
else
|
57
|
+
@layers << Layer.new(neurons, self)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# This traverses the network and initializes all neurons with edges
|
62
|
+
# Initializes with random weights between -5 and 5
|
63
|
+
def initialize_edges
|
64
|
+
@layers.each(&:initialize_neuron_edges)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Sample usage:
|
70
|
+
#
|
71
|
+
# network = Network.new
|
72
|
+
#
|
73
|
+
# network.create_layer(neurons: 10)
|
74
|
+
# network.create_layer(neurons: 2)
|
75
|
+
|
76
|
+
# network.initialize_edges
|
77
|
+
|
78
|
+
# network.run([0.5]*10)
|
data/lib/neuron.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class SimpleNeuralNetwork
|
2
|
+
class Neuron
|
3
|
+
# Define the minimum and maximum edge weight
|
4
|
+
EDGE_RANGE = -5..5
|
5
|
+
|
6
|
+
attr_accessor :bias
|
7
|
+
|
8
|
+
# The neuron parent layer
|
9
|
+
attr_accessor :layer
|
10
|
+
|
11
|
+
# A neuron's edges connect it to the #{layer.next_layer.size} neurons of the next layer
|
12
|
+
attr_accessor :edges
|
13
|
+
|
14
|
+
def initialize(layer)
|
15
|
+
@layer = layer
|
16
|
+
@bias = 0
|
17
|
+
@edges = []
|
18
|
+
@value = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
# A neuron should have one edge per neuron in the next layer
|
22
|
+
def initialize_edges(next_layer_size)
|
23
|
+
next_layer_size.times do
|
24
|
+
@edges << rand(EDGE_RANGE)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: SimpleNeuralNetwork
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nathaniel Woodthorpe
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-02-20 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A very simple neural network implementation in Ruby.
|
14
|
+
email: njwoodthorpe@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/layer.rb
|
20
|
+
- lib/network.rb
|
21
|
+
- lib/neuron.rb
|
22
|
+
- lib/simple_neural_network.rb
|
23
|
+
homepage: https://github.com/d12/SimpleNeuralNetwork
|
24
|
+
licenses:
|
25
|
+
- MIT
|
26
|
+
metadata: {}
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
requirements: []
|
42
|
+
rubyforge_project:
|
43
|
+
rubygems_version: 2.5.2
|
44
|
+
signing_key:
|
45
|
+
specification_version: 4
|
46
|
+
summary: A very simple neural network implementation in Ruby.
|
47
|
+
test_files: []
|