machine_learning_workbench 0.4.0 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -2
- data/lib/machine_learning_workbench/neural_network/base.rb +21 -25
- data/lib/machine_learning_workbench/neural_network/recurrent.rb +19 -11
- data/lib/machine_learning_workbench/optimizer/natural_evolution_strategies/base.rb +1 -1
- data/lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb +2 -3
- data/machine_learning_workbench.gemspec +4 -7
- metadata +29 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05de54fb5221e0b9c4e0a7f59f79ed3b0fb7c166
|
4
|
+
data.tar.gz: da580d26078824e27aff0a518d8a57080d06c2d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50df1af8dc0cfdf8c3ecf3e99553749f25fc562ab022032b31d43bbc7986f17ec2a444a1a60efb06c55f2c85a825986fd45d3f8753ff3eb81b9f51549603e476
|
7
|
+
data.tar.gz: c84df475c3be8175d7c46c83bfdc755803d63c060f1ed7ae4749602003a7f4917726a89412d63011b9d144d241cbf35c24c1cfd871beeae5d379cada304aba23
|
data/.travis.yml
CHANGED
@@ -44,16 +44,15 @@ module MachineLearningWorkbench::NeuralNetwork
|
|
44
44
|
def reset_state
|
45
45
|
state.each do |s|
|
46
46
|
s.fill 0 # reset state to zero
|
47
|
-
s[
|
47
|
+
s[-1] = 1 # add bias
|
48
48
|
end
|
49
|
-
state[-1][
|
49
|
+
state[-1][-1] = 0 # last layer has no bias
|
50
50
|
end
|
51
51
|
|
52
52
|
# Initialize the network with random weights
|
53
53
|
def init_random
|
54
|
-
# Will only be used for testing, no sense optimizing it now (NArray#rand)
|
55
54
|
# Reusing `#load_weights` instead helps catching bugs
|
56
|
-
load_weights nweights.
|
55
|
+
load_weights NArray.new(nweights).rand(-1,1)
|
57
56
|
end
|
58
57
|
|
59
58
|
## Weight utilities
|
@@ -88,10 +87,9 @@ module MachineLearningWorkbench::NeuralNetwork
|
|
88
87
|
end
|
89
88
|
|
90
89
|
# Returns the weight matrix
|
91
|
-
# @return [Array]
|
92
|
-
# matrices, one for each layer.
|
90
|
+
# @return [Array<NArray>] list of NArray matrices of weights (one per layer).
|
93
91
|
def weights
|
94
|
-
layers
|
92
|
+
layers
|
95
93
|
end
|
96
94
|
|
97
95
|
# Number of neurons per layer. Although this implementation includes inputs
|
@@ -126,12 +124,13 @@ module MachineLearningWorkbench::NeuralNetwork
|
|
126
124
|
# all goes well there's nothing to return but a confirmation to the caller.
|
127
125
|
def load_weights weights
|
128
126
|
raise ArgumentError unless weights.size == nweights
|
129
|
-
|
130
|
-
|
131
|
-
layers.
|
132
|
-
|
133
|
-
|
134
|
-
|
127
|
+
weights = weights.to_na unless weights.kind_of? NArray
|
128
|
+
from = 0
|
129
|
+
@layers = layer_shapes.collect do |shape|
|
130
|
+
to = from + shape.reduce(:*)
|
131
|
+
lay_w = weights[from...to].reshape *shape
|
132
|
+
from = to
|
133
|
+
lay_w
|
135
134
|
end
|
136
135
|
reset_state
|
137
136
|
return true
|
@@ -145,52 +144,49 @@ module MachineLearningWorkbench::NeuralNetwork
|
|
145
144
|
# @return [Array] the activation of the output layer
|
146
145
|
def activate input
|
147
146
|
raise ArgumentError unless input.size == struct.first
|
148
|
-
raise ArgumentError unless input.is_a? Array
|
149
147
|
# load input in first state
|
150
|
-
|
148
|
+
state[0][0...struct.first] = input
|
151
149
|
# activate layers in sequence
|
152
150
|
nlayers.times.each do |i|
|
153
151
|
act = activate_layer i
|
154
|
-
|
152
|
+
state[i+1][0...act.size] = act
|
155
153
|
end
|
156
154
|
return out
|
157
155
|
end
|
158
156
|
|
159
157
|
# Extract and convert the output layer's activation
|
160
|
-
# @return [
|
158
|
+
# @return [NArray] the activation of the output layer
|
161
159
|
def out
|
162
|
-
state.last
|
160
|
+
state.last
|
163
161
|
end
|
164
162
|
|
165
|
-
# define #activate_layer in child class
|
166
|
-
|
167
163
|
## Activation functions
|
168
164
|
|
169
165
|
# Traditional sigmoid with variable steepness
|
170
166
|
def sigmoid k=0.5
|
171
167
|
# k is steepness: 0<k<1 is flatter, 1<k is flatter
|
172
168
|
# flatter makes activation less sensitive, better with large number of inputs
|
173
|
-
|
169
|
+
-> (x) { 1.0 / (Numo::NMath.exp(-k * x) + 1.0) }
|
174
170
|
end
|
175
171
|
|
176
172
|
# Traditional logistic
|
177
173
|
def logistic
|
178
|
-
|
174
|
+
-> (x) do
|
179
175
|
exp = Numo::NMath.exp(x)
|
180
176
|
# exp.infinite? ? exp : exp / (1.0 + exp)
|
181
177
|
exp / (1.0 + exp)
|
182
|
-
|
178
|
+
end
|
183
179
|
end
|
184
180
|
|
185
181
|
# LeCun hyperbolic activation
|
186
182
|
# @see http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf Section 4.4
|
187
183
|
def lecun_hyperbolic
|
188
|
-
|
184
|
+
-> (x) { 1.7159 * Numo::NMath.tanh(2.0*x/3.0) + 1e-3*x }
|
189
185
|
end
|
190
186
|
|
191
187
|
# Rectified Linear Unit (ReLU)
|
192
188
|
def relu
|
193
|
-
|
189
|
+
-> (x) { (x>0).all? && x || x.class.zeros(x.shape) }
|
194
190
|
end
|
195
191
|
|
196
192
|
|
@@ -14,21 +14,29 @@ module MachineLearningWorkbench::NeuralNetwork
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
# # NOTE: current layer index corresponds to index of next state!
|
18
|
+
# previous = nlay # index of previous layer (inputs)
|
19
|
+
# current = nlay + 1 # index of current layer (outputs)
|
20
|
+
# # Copy the level's last-time activation to the input (previous state)
|
21
|
+
# # TODO: ranges in `NArray#[]` should be reliable, get rid of loop
|
22
|
+
# nneurs(current).times do |i| # for each activations to copy
|
23
|
+
# # Copy output from last-time activation to recurrency in previous state
|
24
|
+
# @state[previous][0, nneurs(previous) + i] = state[current][0, i]
|
25
|
+
# end
|
26
|
+
# act_fn.call state[previous].dot layers[nlay]
|
27
|
+
|
17
28
|
# Activates a layer of the network.
|
18
29
|
# Bit more complex since it has to copy the layer's activation on
|
19
30
|
# last input to its own inputs, for recursion.
|
20
31
|
# @param i [Integer] the layer to activate, zero-indexed
|
21
|
-
def activate_layer nlay
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
# Copy the level's last-time activation to the input
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@state[previous][0, nneurs(previous) + i] = state[current][0, i]
|
30
|
-
end
|
31
|
-
act_fn.call state[previous].dot layers[nlay]
|
32
|
+
def activate_layer nlay
|
33
|
+
# Mark begin and end of recursion outputs in current state
|
34
|
+
begin_recur = nneurs(nlay)
|
35
|
+
end_recur = nneurs(nlay) + nneurs(nlay+1)
|
36
|
+
# Copy the level's last-time activation to the current input recurrency
|
37
|
+
state[nlay][begin_recur...end_recur] = state[nlay+1][0...nneurs(nlay+1)]
|
38
|
+
# Activate current layer
|
39
|
+
act_fn.call state[nlay].dot layers[nlay]
|
32
40
|
end
|
33
41
|
|
34
42
|
end
|
@@ -119,7 +119,7 @@ module MachineLearningWorkbench::Optimizer::NaturalEvolutionStrategies
|
|
119
119
|
|
120
120
|
sort_idxs = fits.sort_index
|
121
121
|
sort_idxs = sort_idxs.reverse if opt_type == :min
|
122
|
-
this_best = [fits[sort_idxs[-1]], inds[sort_idxs[-1]]]
|
122
|
+
this_best = [fits[sort_idxs[-1]], inds[sort_idxs[-1], true]]
|
123
123
|
|
124
124
|
opt_cmp_fn = opt_type==:min ? :< : :>
|
125
125
|
@best = this_best if this_best.first.send(opt_cmp_fn, best.first)
|
@@ -5,8 +5,7 @@ module MachineLearningWorkbench::Optimizer::NaturalEvolutionStrategies
|
|
5
5
|
|
6
6
|
MAX_RSEED = 10**Random.new_seed.size # same range as Random.new_seed
|
7
7
|
|
8
|
-
attr_reader :ndims_lst, :
|
9
|
-
:best, :last_fits
|
8
|
+
attr_reader :ndims_lst, :blocks, :popsize
|
10
9
|
|
11
10
|
# Initialize a list of XNES, one for each block
|
12
11
|
# see class `Base` for the description of the rest of the arguments.
|
@@ -67,7 +66,7 @@ module MachineLearningWorkbench::Optimizer::NaturalEvolutionStrategies
|
|
67
66
|
# sorted_samples = sorted.map(&:last)
|
68
67
|
sort_idxs = fits.sort_index
|
69
68
|
sort_idxs = sort_idxs.reverse if opt_type == :min
|
70
|
-
this_best = [fits[sort_idxs[-1]], full_inds[sort_idxs[-1]]]
|
69
|
+
this_best = [fits[sort_idxs[-1]], full_inds[sort_idxs[-1], true]]
|
71
70
|
opt_cmp_fn = opt_type==:min ? :< : :>
|
72
71
|
@best = this_best if this_best.first.send(opt_cmp_fn, best.first)
|
73
72
|
sorted_samples = full_samples.values_at *sort_idxs
|
@@ -34,21 +34,18 @@ Gem::Specification.new do |spec|
|
|
34
34
|
|
35
35
|
# Test
|
36
36
|
spec.add_development_dependency "rspec", "~> 3.0"
|
37
|
-
spec.add_development_dependency "rmagick" #
|
37
|
+
spec.add_development_dependency "rmagick" # uhm would gladly drop this
|
38
38
|
|
39
39
|
# Debug
|
40
40
|
spec.add_development_dependency "pry", "~> 0.10"
|
41
41
|
spec.add_development_dependency "pry-nav", "~> 0.2"
|
42
42
|
spec.add_development_dependency "pry-rescue", "~> 1.4"
|
43
43
|
spec.add_development_dependency "pry-stack_explorer", "~> 0.4"
|
44
|
+
spec.add_development_dependency "pry-doc", "~> 0.12"
|
44
45
|
|
45
46
|
# Run
|
46
47
|
spec.requirements << "libopenblas-base" # library for following dependency
|
47
|
-
spec.add_dependency "numo-
|
48
|
+
spec.add_dependency "numo-narray", "~> 0.9"
|
49
|
+
spec.add_dependency "numo-linalg", "~> 0.1"
|
48
50
|
spec.add_dependency "parallel", "~> 1.12"
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
# DELETEME
|
53
|
-
spec.add_dependency "nmatrix-atlas"
|
54
51
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: machine_learning_workbench
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Giuseppe Cuccu
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-03-
|
11
|
+
date: 2018-03-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -123,47 +123,61 @@ dependencies:
|
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0.4'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
126
|
+
name: pry-doc
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
|
-
- - "
|
129
|
+
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '0'
|
131
|
+
version: '0.12'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0.12'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: numo-narray
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0.9'
|
132
146
|
type: :runtime
|
133
147
|
prerelease: false
|
134
148
|
version_requirements: !ruby/object:Gem::Requirement
|
135
149
|
requirements:
|
136
|
-
- - "
|
150
|
+
- - "~>"
|
137
151
|
- !ruby/object:Gem::Version
|
138
|
-
version: '0'
|
152
|
+
version: '0.9'
|
139
153
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
154
|
+
name: numo-linalg
|
141
155
|
requirement: !ruby/object:Gem::Requirement
|
142
156
|
requirements:
|
143
157
|
- - "~>"
|
144
158
|
- !ruby/object:Gem::Version
|
145
|
-
version: '1
|
159
|
+
version: '0.1'
|
146
160
|
type: :runtime
|
147
161
|
prerelease: false
|
148
162
|
version_requirements: !ruby/object:Gem::Requirement
|
149
163
|
requirements:
|
150
164
|
- - "~>"
|
151
165
|
- !ruby/object:Gem::Version
|
152
|
-
version: '1
|
166
|
+
version: '0.1'
|
153
167
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
168
|
+
name: parallel
|
155
169
|
requirement: !ruby/object:Gem::Requirement
|
156
170
|
requirements:
|
157
|
-
- - "
|
171
|
+
- - "~>"
|
158
172
|
- !ruby/object:Gem::Version
|
159
|
-
version: '
|
173
|
+
version: '1.12'
|
160
174
|
type: :runtime
|
161
175
|
prerelease: false
|
162
176
|
version_requirements: !ruby/object:Gem::Requirement
|
163
177
|
requirements:
|
164
|
-
- - "
|
178
|
+
- - "~>"
|
165
179
|
- !ruby/object:Gem::Version
|
166
|
-
version: '
|
180
|
+
version: '1.12'
|
167
181
|
description: |-
|
168
182
|
This workbench holds a collection of machine learning
|
169
183
|
methods in Ruby. Rather than specializing on a single task or method, this
|