bp_net 0.0.2
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/bp_net.rb +108 -0
- metadata +43 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4ae78900480ba50a21932b089dfb61c8008e4094255da4c76f1b8897ee3a9b8b
|
4
|
+
data.tar.gz: ea012ac44327f5e91df5da58c131c0df5a637aa27a613200ae21b1a2f2ed92f7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9fe9e7a877f4dbc80c403bcb072bf9051dc9c77a7ad182ce5a4f737beb3d0e082e6fa7b40af6bd4ce954c919d17d0b11e7dd9b49ccac0b1ec01b0e37910a5fbe
|
7
|
+
data.tar.gz: e4b2b7e6a1269ea7659e0de5bb8ade20e247172490a74432e6aa3a0a219ba3c0ba1f037fa4b5d15ef2b1d40d92cc5b23e4047037f7a0286499de2476874b7f8f
|
data/lib/bp_net.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'matrix'
|
2
|
+
|
3
|
+
class Matrix
|
4
|
+
def disp(line_feed: 1)
|
5
|
+
row_vectors.each do |row| # self.row_vectors...
|
6
|
+
row.each do |ele| # print elements by row
|
7
|
+
print "#{ele}\t"
|
8
|
+
end
|
9
|
+
line_feed.times { puts } # Line Feed
|
10
|
+
end
|
11
|
+
self
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class BpNet
|
16
|
+
# accessable attributes
|
17
|
+
ACCESSABLE_ATTRS = %i[inodes hnodes onodes lr wih who]
|
18
|
+
attr_accessor(*ACCESSABLE_ATTRS)
|
19
|
+
|
20
|
+
# initialization
|
21
|
+
def initialize(inputnodes:, hiddennodes:, outputnodes:, learningrate:)
|
22
|
+
@inodes = inputnodes # input nodes
|
23
|
+
@hnodes = hiddennodes # hidden nodes
|
24
|
+
@onodes = outputnodes # output nodes
|
25
|
+
@lr = learningrate # learning rate
|
26
|
+
|
27
|
+
# weight matrixes
|
28
|
+
@wih = Matrix.build(hiddennodes, inputnodes) { rand - 0.5 }
|
29
|
+
@who = Matrix.build(outputnodes, hiddennodes) { rand - 0.5 }
|
30
|
+
end
|
31
|
+
|
32
|
+
# train
|
33
|
+
def train(inputs_mat, targets_mat)
|
34
|
+
inputs_mat = arr2mat(inputs_mat) # convert array to matrix
|
35
|
+
targets_mat = arr2mat(targets_mat) # convert arr 2 mat
|
36
|
+
|
37
|
+
hidden_inputs = @wih * inputs_mat # Hi = Wih * I
|
38
|
+
hidden_outputs = BpNet.sigmoid(hidden_inputs) # H = sigmoid(Hi)
|
39
|
+
outputs_inputs = @who * hidden_outputs # Oi = Who * H
|
40
|
+
outputs_outputs = BpNet.sigmoid(outputs_inputs) # O = sigmoid(Oi)
|
41
|
+
|
42
|
+
output_errors = targets_mat - outputs_outputs
|
43
|
+
@who += update(output_errors, outputs_inputs, hidden_outputs)
|
44
|
+
|
45
|
+
hidden_errors = @who.t * output_errors
|
46
|
+
@wih += update(hidden_errors, hidden_inputs, inputs_mat)
|
47
|
+
end
|
48
|
+
|
49
|
+
# query
|
50
|
+
# Hi = Wih * I
|
51
|
+
# H = sigmoid(Hi)
|
52
|
+
# Oi = Who * H
|
53
|
+
# O = sigmoid(Oi)
|
54
|
+
def query(inputs_mat)
|
55
|
+
inputs_mat = arr2mat(inputs_mat) # convert array to matrix
|
56
|
+
|
57
|
+
hidden_inputs = @wih * inputs_mat # Hi = Wih * I
|
58
|
+
hidden_outputs = BpNet.sigmoid(hidden_inputs) # H = sigmoid(Hi)
|
59
|
+
outputs_inputs = @who * hidden_outputs # Oi = Who * H
|
60
|
+
outputs_outputs = BpNet.sigmoid(outputs_inputs) # O = sigmoid(Oi)
|
61
|
+
end
|
62
|
+
|
63
|
+
def arr2mat(arr)
|
64
|
+
if arr.is_a? Array
|
65
|
+
Matrix[arr].t
|
66
|
+
else
|
67
|
+
arr
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
## calculations goes here
|
72
|
+
# singular sigmoid
|
73
|
+
@singular_sigmoid = ->(x) { 1 / (1 + Math::E**-x) }
|
74
|
+
|
75
|
+
# singular sigmoid differentiation
|
76
|
+
@singular_sigmoid_diff = lambda do |x|
|
77
|
+
@singular_sigmoid.call(x) * (1 - @singular_sigmoid.call(x))
|
78
|
+
end
|
79
|
+
|
80
|
+
def update(errors, next_inputs, prev_outputs)
|
81
|
+
@lr *
|
82
|
+
errors.hadamard_product(BpNet.sigmoid_diff(next_inputs)) *
|
83
|
+
prev_outputs.t
|
84
|
+
end
|
85
|
+
|
86
|
+
## packed enumerable calculations
|
87
|
+
# sigmoid
|
88
|
+
def self.sigmoid(x)
|
89
|
+
enum_calc(x, @singular_sigmoid) { |param| sigmoid(param) }
|
90
|
+
end
|
91
|
+
|
92
|
+
# sigmoid differentiation
|
93
|
+
def self.sigmoid_diff(x)
|
94
|
+
enum_calc(x, @singular_sigmoid_diff) { |param| sigmoid_diff(param) }
|
95
|
+
end
|
96
|
+
|
97
|
+
## enumerable calculation
|
98
|
+
def self.enum_calc(x, calc, &block)
|
99
|
+
if x.is_a? Enumerable
|
100
|
+
x.map(&block) # return values recursively
|
101
|
+
else
|
102
|
+
calc.call(x) # return value
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# private class methods
|
107
|
+
private_class_method :enum_calc
|
108
|
+
end
|
metadata
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bp_net
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rurika Misaka
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-05-08 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A sipmle BP Neural Network gem
|
14
|
+
email: goblinmaiden1931@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/bp_net.rb
|
20
|
+
homepage:
|
21
|
+
licenses:
|
22
|
+
- MIT
|
23
|
+
metadata: {}
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
requirements: []
|
39
|
+
rubygems_version: 3.2.3
|
40
|
+
signing_key:
|
41
|
+
specification_version: 4
|
42
|
+
summary: Simple BP Neural Network
|
43
|
+
test_files: []
|