qoa 0.0.3 → 0.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a45d057fc9994389ef429aa82b3207a2e30b8e67a880f3ad6e6b57f7e7a79b75
4
- data.tar.gz: 273f73d4184545b75ec338f75c9ea39b5e4e2cc6e2582091bab036e93f06b320
3
+ metadata.gz: 8541feace7b5d8df6418672899fbba8289cc63624d7876c640a28e3143a450f3
4
+ data.tar.gz: 3944346b90a422a1ea843aef9b0a5bd18c8067e0bc075fa897daab0a1cf9373c
5
5
  SHA512:
6
- metadata.gz: 00eedcfdee31e73c559be6b8c3e75d31c72d2f802a40e9322c82b0bfe6e615ce9f2498d559722fa360d9ebb7d23328f8275c94374b40651d82e3705f869e413a
7
- data.tar.gz: c125116a1e5deb7d345315eaa9954e006b198a881864b123b452906dcd1d009f473bbfc82a7cd7f09a67dca7c61de83aefb8156eed4cfde8b5d593858448c017
6
+ metadata.gz: 8e0afee3076f2d47ff091c2d943c53710e080b015f2773733aabaf90fc4b2ccb26507d24344d1e3b6915e488df875b093577098572c889a1a621064600467037
7
+ data.tar.gz: aaf6f8e7e9280630fd6218d72a6dd47a4e68602b193a127be8b59462e3204267a28e490e61e8dc19523b8aa463f2d9611fd81617b9da9f79d0e83b1c1942a638
data/README.md CHANGED
@@ -10,6 +10,7 @@ Qoa is a simple and customizable neural network library for Ruby. It allows you
10
10
  - Weight initialization using Xavier initialization
11
11
  - Customizable learning parameters
12
12
  - Parallelized backward pass for faster training
13
+ - Supports convolutional and pooling layers
13
14
 
14
15
  ## Installation
15
16
 
@@ -34,7 +35,7 @@ require 'qoa'
34
35
  To create a new neural network, you can initialize an instance of `Qoa::NeuralNetwork` with the following parameters:
35
36
 
36
37
  - `input_nodes`: The number of input nodes.
37
- - `hidden_layers`: An array of the number of nodes in each hidden layer.
38
+ - `hidden_layers`: An array of the number of nodes in each hidden layer, or an array of `[:conv, nodes, kernel_size, stride]` for a convolutional layer or `[:pool, nodes, pool_size, stride]` for a pooling layer.
38
39
  - `output_nodes`: The number of output nodes.
39
40
  - `learning_rate`: The learning rate for the gradient descent optimization.
40
41
  - `dropout_rate`: The dropout rate for regularization.
@@ -42,6 +43,8 @@ To create a new neural network, you can initialize an instance of `Qoa::NeuralNe
42
43
  - `decay_rate`: The decay rate for the RMSProp optimizer (default is `0.9`).
43
44
  - `epsilon`: A small value to prevent division by zero in the RMSProp optimizer (default is `1e-8`).
44
45
  - `batch_size`: The size of the mini-batches used for training (default is `10`).
46
+ - `l1_lambda`: The L1 regularization parameter (default is `0.0`).
47
+ - `l2_lambda`: The L2 regularization parameter (default is `0.0`).
45
48
 
46
49
  Example:
47
50
 
@@ -49,7 +52,7 @@ Example:
49
52
  require 'qoa'
50
53
 
51
54
  input_nodes = 784 # Number of input features (e.g., 28x28 pixels for MNIST dataset)
52
- hidden_layers = [128, 64] # Two hidden layers with 128 and 64 nodes each
55
+ hidden_layers = [128, [:conv, 64, 3, 1]] # One hidden layer with 128 nodes and one convolutional layer with 64 nodes, kernel size 3, and stride 1
53
56
  output_nodes = 10 # Number of output classes (e.g., 10 for MNIST dataset)
54
57
  learning_rate = 0.01
55
58
  dropout_rate = 0.5
@@ -0,0 +1,27 @@
1
+ module Qoa
2
+ module Err
3
+ module Validations
4
+ def validate_constructor_args(input_nodes, hidden_layers, output_nodes, learning_rate, dropout_rate, activation_func, decay_rate, epsilon, batch_size, l1_lambda, l2_lambda)
5
+ raise ArgumentError, 'input_nodes, hidden_layers, and output_nodes must be positive integers' unless [input_nodes, output_nodes].all? { |x| x.is_a?(Integer) && x > 0 } && hidden_layers.is_a?(Array) && hidden_layers.all? { |x| x.is_a?(Integer) && x > 0 }
6
+ raise ArgumentError, 'learning_rate, dropout_rate, decay_rate, epsilon, l1_lambda, and l2_lambda must be positive numbers' unless [learning_rate, dropout_rate, decay_rate, epsilon, l1_lambda, l2_lambda].all? { |x| x.is_a?(Numeric) && x >= 0 }
7
+ raise ArgumentError, 'activation_func must be a valid symbol' unless ActivationFunctions.methods.include?(activation_func)
8
+ raise ArgumentError, 'batch_size must be a positive integer' unless batch_size.is_a?(Integer) && batch_size > 0
9
+ end
10
+
11
+ def validate_query_args(inputs)
12
+ raise ArgumentError, 'inputs must be an array of numbers' unless inputs.is_a?(Array) && inputs.all? { |x| x.is_a?(Numeric) }
13
+ end
14
+
15
+ def validate_calculate_loss_args(inputs, targets, loss_function)
16
+ raise ArgumentError, 'inputs and targets must have the same length' if inputs.size != targets.size
17
+ raise ArgumentError, 'inputs and targets must be arrays of arrays of numbers' unless inputs.is_a?(Array) && targets.is_a?(Array) && inputs.all? { |x| x.is_a?(Array) && x.all? { |y| y.is_a?(Numeric) } } && targets.all? { |x| x.is_a?(Array) && x.all? { |y| y.is_a?(Numeric) } }
18
+ raise ArgumentError, 'loss_function must be a valid symbol' unless LossFunctions.methods.include?(loss_function)
19
+ end
20
+
21
+ def validate_train_args(inputs, targets)
22
+ raise ArgumentError, 'inputs and targets must have the same length' if inputs.size != targets.size
23
+ raise ArgumentError, 'inputs and targets must be arrays of arrays of numbers' unless inputs.is_a?(Array) && targets.is_a?(Array) && inputs.all? { |x| x.is_a?(Array) && x.all? { |y| y.is_a?(Numeric) } } && targets.all? { |x| x.is_a?(Array) && x.all? { |y| y.is_a?(Numeric) } }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ module Qoa
2
+ module Layers
3
+ class ConvolutionalLayer < Qoa::Layers::Layer
4
+ attr_reader :kernel_size, :stride
5
+
6
+ def initialize(input_size, output_size, kernel_size, stride = 1)
7
+ super(input_size, output_size)
8
+ @kernel_size = kernel_size
9
+ @stride = stride
10
+ end
11
+
12
+ def random_matrix(rows, cols)
13
+ limit = Math.sqrt(6.0 / (rows + cols))
14
+ Array.new(rows) { Array.new(cols) { rand(-limit..limit) } }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ module Qoa
2
+ module Layers
3
+ class Layer
4
+ attr_reader :input_size, :output_size, :weights
5
+
6
+ def initialize(input_size, output_size)
7
+ @input_size = input_size
8
+ @output_size = output_size
9
+ @weights = random_matrix(output_size, input_size)
10
+ end
11
+
12
+ def random_matrix(rows, cols)
13
+ limit = Math.sqrt(6.0 / (rows + cols))
14
+ Array.new(rows) { Array.new(cols) { rand(-limit..limit) } }
15
+ end
16
+
17
+ def weights=(new_weights)
18
+ @weights = new_weights
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ module Qoa
2
+ module Layers
3
+ class PoolingLayer < Qoa::Layers::Layer
4
+ attr_reader :pool_size, :stride
5
+
6
+ def initialize(input_size, output_size, pool_size, stride = 1)
7
+ super(input_size, output_size)
8
+ @pool_size = pool_size
9
+ @stride = stride
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,30 @@
1
+ module Qoa
2
+ module LossFunctions
3
+ class << self
4
+ def mean_squared_error(prediction, target)
5
+ raise ArgumentError, 'prediction and target must have the same length' if prediction.size != target.size
6
+ prediction.zip(target).map { |p, t| (p - t) ** 2 }.sum / prediction.size
7
+ end
8
+
9
+ def cross_entropy_loss(prediction, target)
10
+ raise ArgumentError, 'prediction and target must have the same length' if prediction.size != target.size
11
+ -prediction.zip(target).map { |p, t| t * Math.log(p) }.sum / prediction.size
12
+ end
13
+
14
+ def binary_cross_entropy(prediction, target)
15
+ raise ArgumentError, 'prediction and target must have the same length' if prediction.size != target.size
16
+ -prediction.zip(target).map { |p, t| t * Math.log(p) + (1 - t) * Math.log(1 - p) }.sum / prediction.size
17
+ end
18
+
19
+ def categorical_cross_entropy(prediction, target)
20
+ raise ArgumentError, 'prediction and target must have the same length' if prediction.size != target.size
21
+ -prediction.zip(target).map { |p, t| t * Math.log(p) }.sum / prediction.size
22
+ end
23
+
24
+ def mean_absolute_error(prediction, target)
25
+ raise ArgumentError, 'prediction and target must have the same length' if prediction.size != target.size
26
+ prediction.zip(target).map { |p, t| (p - t).abs }.sum / prediction.size
27
+ end
28
+ end
29
+ end
30
+ end
@@ -24,7 +24,11 @@ module Qoa
24
24
  end
25
25
 
26
26
  def apply_function(matrix, func)
27
- matrix.map { |row| row.map { |x| func.call(x) } }
27
+ matrix.map do |row|
28
+ row.map do |x|
29
+ x.nil? ? nil : func.call(x) # Add a check for nil values
30
+ end
31
+ end
28
32
  end
29
33
 
30
34
  def transpose(matrix)
@@ -1,15 +1,24 @@
1
- require_relative 'layer'
1
+ require_relative 'layers/layer'
2
+ require_relative 'layers/convolutional_layer'
3
+ require_relative 'layers/pooling_layer'
2
4
  require_relative 'activation_functions'
3
5
  require_relative 'training'
4
6
  require_relative 'utils'
7
+ require_relative 'loss_functions'
8
+ require_relative 'err/validations'
5
9
 
6
10
  module Qoa
7
11
  class NeuralNetwork
8
12
  include Training
9
13
  include Utils
10
- attr_reader :input_nodes, :hidden_layers, :output_nodes, :learning_rate, :activation_func, :dropout_rate, :decay_rate, :epsilon, :batch_size
14
+ include LossFunctions
15
+ include Err::Validations
16
+
17
+ attr_reader :input_nodes, :hidden_layers, :output_nodes, :learning_rate, :activation_func, :dropout_rate, :decay_rate, :epsilon, :batch_size, :l1_lambda, :l2_lambda
18
+
19
+ def initialize(input_nodes, hidden_layers, output_nodes, learning_rate, dropout_rate, activation_func = :leaky_relu, decay_rate = 0.9, epsilon = 1e-8, batch_size = 10, l1_lambda = 0.0, l2_lambda = 0.0)
20
+ # validate_constructor_args(input_nodes, hidden_layers, output_nodes, learning_rate, dropout_rate, activation_func, decay_rate, epsilon, batch_size, l1_lambda, l2_lambda)
11
21
 
12
- def initialize(input_nodes, hidden_layers, output_nodes, learning_rate, dropout_rate, activation_func = :sigmoid, decay_rate = 0.9, epsilon = 1e-8, batch_size = 10)
13
22
  @input_nodes = input_nodes
14
23
  @hidden_layers = hidden_layers
15
24
  @output_nodes = output_nodes
@@ -19,27 +28,47 @@ module Qoa
19
28
  @decay_rate = decay_rate
20
29
  @epsilon = epsilon
21
30
  @batch_size = batch_size
31
+ @l1_lambda = l1_lambda
32
+ @l2_lambda = l2_lambda
22
33
 
23
34
  @layers = []
24
- @layers << Layer.new(input_nodes, hidden_layers[0])
35
+ @layers << Qoa::Layers::Layer.new(input_nodes, hidden_layers[0].is_a?(Array) ? hidden_layers[0][1] : hidden_layers[0])
36
+
25
37
  hidden_layers.each_cons(2) do |l1, l2|
26
- @layers << Layer.new(l1, l2)
38
+ l1_size = l1.is_a?(Array) ? l1[1] : l1
39
+ l2_size = l2.is_a?(Array) ? l2[1] : l2
40
+
41
+ if l1.is_a?(Array) && l2.is_a?(Array) && l1[0] == :conv && l2[0] == :conv
42
+ @layers << Qoa::Layers::ConvolutionalLayer.new(l1_size, l2_size, l1[2], l1[3])
43
+ elsif l1.is_a?(Array) && l1[0] == :conv && l2.is_a?(Numeric)
44
+ @layers << Qoa::Layers::ConvolutionalLayer.new(l1_size, l2_size, l1[2], l1[3])
45
+ elsif l1.is_a?(Numeric) && l2.is_a?(Array) && l2[0] == :conv
46
+ @layers << Qoa::Layers::ConvolutionalLayer.new(l1_size, l2_size, l2[2], l2[3])
47
+ elsif l1.is_a?(Array) && l1[0] == :pool && l2.is_a?(Numeric)
48
+ @layers << Qoa::Layers::PoolingLayer.new(l1_size, l2_size, l1[2], l1[3])
49
+ elsif l1.is_a?(Numeric) && l2.is_a?(Array) && l2[0] == :pool
50
+ @layers << Qoa::Layers::PoolingLayer.new(l1_size, l2_size, l2[2], l2[3])
51
+ else
52
+ @layers << Qoa::Layers::Layer.new(l1_size, l2_size)
53
+ end
27
54
  end
28
- @layers << Layer.new(hidden_layers[-1], output_nodes)
55
+ @layers << Qoa::Layers::Layer.new(hidden_layers[-1].is_a?(Array) ? hidden_layers[-1][1] : hidden_layers[-1], output_nodes)
29
56
  end
30
57
 
31
58
  def query(inputs)
59
+ validate_query_args(inputs)
60
+
32
61
  layer_outputs = forward_pass(inputs)
33
62
  layer_outputs.last.flatten
34
63
  end
35
64
 
36
- def calculate_loss(inputs, targets)
37
- raise ArgumentError, 'inputs and targets must have the same length' if inputs.size != targets.size
65
+ def calculate_loss(inputs, targets, loss_function = :cross_entropy_loss)
66
+ validate_calculate_loss_args(inputs, targets, loss_function)
38
67
 
39
68
  total_loss = 0.0
40
69
  inputs.zip(targets).each do |input, target|
41
70
  prediction = query(input)
42
- total_loss += mean_squared_error(prediction, target)
71
+ total_loss += LossFunctions.send(loss_function, prediction, target)
43
72
  end
44
73
 
45
74
  total_loss / inputs.size
data/lib/qoa/training.rb CHANGED
@@ -1,12 +1,14 @@
1
- require_relative 'matrix_helpers'
2
1
  require 'concurrent'
2
+ require_relative 'matrix_helpers'
3
+ require_relative 'err/validations'
3
4
 
4
5
  module Qoa
5
6
  module Training
6
7
  include MatrixHelpers
8
+ include Err::Validations
7
9
 
8
10
  def train(inputs, targets)
9
- raise ArgumentError, 'inputs and targets must have the same length' if inputs.size != targets.size
11
+ validate_train_args(inputs, targets)
10
12
 
11
13
  inputs.zip(targets).each_slice(@batch_size) do |batch|
12
14
  train_batch(batch)
@@ -44,7 +46,8 @@ module Qoa
44
46
 
45
47
  # Update weights
46
48
  @layers.each_with_index do |layer, i|
47
- layer.weights = matrix_add(layer.weights, scalar_multiply(@learning_rate / batch.size, weight_deltas[i]))
49
+ regularization_penalty = calculate_regularization_penalty(layer.weights, @l1_lambda, @l2_lambda)
50
+ layer.weights = matrix_add(layer.weights, scalar_multiply(@learning_rate / batch.size, matrix_add(weight_deltas[i], regularization_penalty)))
48
51
  end
49
52
  end
50
53
 
@@ -77,8 +80,15 @@ module Qoa
77
80
  inputs = inputs.map { |x| [x] } # Convert to column vector
78
81
 
79
82
  layer_outputs = [inputs]
80
- @layers.map(&:weights).each_with_index do |w, i|
81
- layer_inputs = matrix_multiply(w, layer_outputs[-1])
83
+ @layers.each_with_index do |layer, i|
84
+ if layer.is_a?(Qoa::Layers::ConvolutionalLayer)
85
+ layer_inputs = convolution(layer, layer_outputs[-1])
86
+ elsif layer.is_a?(Qoa::Layers::PoolingLayer)
87
+ layer_inputs = pooling(layer, layer_outputs[-1])
88
+ else
89
+ layer_inputs = matrix_multiply(layer.weights, layer_outputs[-1])
90
+ end
91
+
82
92
  layer_outputs << apply_function(layer_inputs, ActivationFunctions.method(@activation_func))
83
93
 
84
94
  # Apply dropout to hidden layers
@@ -101,13 +111,96 @@ module Qoa
101
111
 
102
112
  # Compute weight deltas
103
113
  weight_deltas = []
104
- @layers.each_with_index do |_, i|
114
+ @layers.each_with_index do |layer, i|
105
115
  gradients = matrix_multiply_element_wise(errors[i], apply_function(layer_outputs[i + 1], ActivationFunctions.method(derivative_func)))
106
- w_delta = matrix_multiply(gradients, transpose(layer_outputs[i]))
116
+ if layer.is_a?(Qoa::Layers::ConvolutionalLayer)
117
+ w_delta = conv_weight_delta(layer, gradients, layer_outputs[i])
118
+ elsif layer.is_a?(Qoa::Layers::PoolingLayer)
119
+ w_delta = pool_weight_delta(layer, gradients, layer_outputs[i])
120
+ else
121
+ w_delta = matrix_multiply(gradients, transpose(layer_outputs[i]))
122
+ end
107
123
  weight_deltas << w_delta
108
124
  end
109
125
 
110
126
  weight_deltas
111
127
  end
128
+
129
+ def calculate_regularization_penalty(weights, l1_lambda, l2_lambda)
130
+ l1_penalty = weights.map do |row|
131
+ row.nil? ? nil : row.map { |x| x.nil? ? nil : (x < 0 ? -1 : 1) }
132
+ end
133
+ l1_penalty = scalar_multiply(l1_lambda, l1_penalty)
134
+
135
+ l2_penalty = scalar_multiply(l2_lambda, weights)
136
+
137
+ matrix_add(l1_penalty, l2_penalty)
138
+ end
139
+
140
+ def convolution(layer, inputs)
141
+ output_size = layer.output_size
142
+ kernel_size = layer.kernel_size
143
+ stride = layer.stride
144
+
145
+ output = Array.new(output_size) { Array.new(inputs.length - kernel_size + 1) }
146
+ layer.weights.each_with_index do |row, i|
147
+ inputs.each_cons(kernel_size).each_with_index do |input_slice, j|
148
+ output[i][j] = row.zip(input_slice).map { |a, b| a * b }.reduce(:+)
149
+ end
150
+ end
151
+
152
+ output
153
+ end
154
+
155
+ def pooling(layer, inputs)
156
+ output_size = layer.output_size
157
+ pool_size = layer.pool_size
158
+ stride = layer.stride || 1
159
+
160
+ # Calculate the number of columns in the output array
161
+ output_columns = inputs[0].length - pool_size
162
+ output_columns = output_columns <= 0 ? 1 : ((output_columns) / stride.to_f).ceil + 1
163
+
164
+ output = Array.new(output_size) { Array.new(output_columns) }
165
+
166
+ (0...output_size).each do |i|
167
+ (0...output_columns).each do |j|
168
+ start_idx = j * stride
169
+ end_idx = start_idx + pool_size - 1
170
+ next if inputs[i].nil? || inputs[i].length < end_idx + 1 # Add this check to avoid accessing an index that does not exist
171
+ pool_slice = inputs[i].slice(start_idx..end_idx)
172
+ output[i][j] = pool_slice.max
173
+ end
174
+ end
175
+
176
+ output
177
+ end
178
+
179
+ def conv_weight_delta(layer, gradients, inputs)
180
+ kernel_size = layer.kernel_size
181
+ stride = layer.stride
182
+
183
+ deltas = layer.weights.map do |row|
184
+ inputs.each_cons(kernel_size).map do |input_slice|
185
+ row.zip(input_slice).map { |a, b| a * b }.reduce(:+)
186
+ end
187
+ end
188
+
189
+ deltas
190
+ end
191
+
192
+ def pool_weight_delta(layer, gradients, inputs)
193
+ pool_size = layer.pool_size
194
+ stride = layer.stride
195
+
196
+ deltas = inputs.each_slice(stride).map do |input_slice|
197
+ input_slice.each_cons(pool_size).map do |pool_slice|
198
+ max_index = pool_slice.each_with_index.max[1]
199
+ pool_slice.map.with_index { |v, i| (i == max_index) ? v * gradients[i] : 0 }
200
+ end
201
+ end
202
+
203
+ deltas
204
+ end
112
205
  end
113
206
  end
data/lib/qoa/utils.rb CHANGED
@@ -34,16 +34,10 @@ module Qoa
34
34
  @epsilon = model_data[:epsilon]
35
35
  @batch_size = model_data[:batch_size]
36
36
 
37
- @layers = model_data[:weights].map { |w| Layer.new(w.first.size, w.size) }
37
+ @layers = model_data[:weights].map { |w| Qoa::Layers::Layer.new(w.first.size, w.size) }
38
38
  @layers.each_with_index do |layer, i|
39
39
  layer.weights = model_data[:weights][i]
40
40
  end
41
41
  end
42
-
43
- def mean_squared_error(prediction, target)
44
- raise ArgumentError, 'prediction and target must have the same length' if prediction.size != target.size
45
-
46
- prediction.zip(target).map { |p, t| (p - t) ** 2 }.sum / prediction.size
47
- end
48
42
  end
49
43
  end
data/lib/qoa/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Qoa
2
- VERSION = '0.0.3'
2
+ VERSION = '0.0.4'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qoa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel M. Matongo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-01 00:00:00.000000000 Z
11
+ date: 2023-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: concurrent-ruby
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.1'
55
69
  description: Qoa is a simple machine learning library for Ruby, including a basic
56
70
  feedforward neural network implementation with backpropagation.
57
71
  email:
@@ -65,7 +79,11 @@ files:
65
79
  - code_of_conduct.md
66
80
  - lib/qoa.rb
67
81
  - lib/qoa/activation_functions.rb
68
- - lib/qoa/layer.rb
82
+ - lib/qoa/err/validations.rb
83
+ - lib/qoa/layers/convolutional_layer.rb
84
+ - lib/qoa/layers/layer.rb
85
+ - lib/qoa/layers/pooling_layer.rb
86
+ - lib/qoa/loss_functions.rb
69
87
  - lib/qoa/matrix_helpers.rb
70
88
  - lib/qoa/neural_network.rb
71
89
  - lib/qoa/training.rb
data/lib/qoa/layer.rb DELETED
@@ -1,20 +0,0 @@
1
- module Qoa
2
- class Layer
3
- attr_reader :input_size, :output_size, :weights
4
-
5
- def initialize(input_size, output_size)
6
- @input_size = input_size
7
- @output_size = output_size
8
- @weights = random_matrix(output_size, input_size)
9
- end
10
-
11
- def random_matrix(rows, cols)
12
- limit = Math.sqrt(6.0 / (rows + cols))
13
- Array.new(rows) { Array.new(cols) { rand(-limit..limit) } }
14
- end
15
-
16
- def weights=(new_weights)
17
- @weights = new_weights
18
- end
19
- end
20
- end