machine_learning_workbench 0.4.0 → 0.4.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 +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
|