machine_learning_workbench 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/machine_learning_workbench/compressor.rb +2 -1
- data/lib/machine_learning_workbench/compressor/copy_vq.rb +47 -0
- data/lib/machine_learning_workbench/compressor/{online_vector_quantization.rb → decaying_learning_rate_vq.rb} +2 -2
- data/lib/machine_learning_workbench/compressor/vector_quantization.rb +42 -23
- data/lib/machine_learning_workbench/neural_network/base.rb +5 -13
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0677a5bd2af361c57794f13c2c62ceb353bab987
|
4
|
+
data.tar.gz: 160f5d7f06abc3c4520a7753cd4fa0f155bbb09e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7e2872adb965b394cfc23c0cdd16f905e336c17ef0f91f7f53a05abc32a5e176720e9adaa163430898b80f873213dacda8fbfe346fc49c0cee589f1b6830cee
|
7
|
+
data.tar.gz: 49671433cb861a17a73414c0cd1c5b4f3249122ea809dec4ed2c7c14ddd4587cdbb1f8c688d5bdb59ab0d97adf4ff81ac0b4c3911c3344c5c5677a26e96942cf
|
data/README.md
CHANGED
@@ -58,4 +58,4 @@ Please feel free to contribute to this list (see `Contributing` above).
|
|
58
58
|
- **UL-ELR** stands for Unsupervised Learning plus Evolutionary Reinforcement Learning, from the paper _"Intrinsically Motivated Neuroevolution for Vision-Based Reinforcement Learning" (ICDL2011)_. Check [here](https://exascale.info/members/giuseppe-cuccu/) for citation reference and pdf.
|
59
59
|
- **BD-NES** stands for Block Diagonal Natural Evolution Strategy, from the homonymous paper _"Block Diagonal Natural Evolution Strategies" (PPSN2012)_. Check [here](https://exascale.info/members/giuseppe-cuccu/) for citation reference and pdf.
|
60
60
|
- **RNES** stands for Radial Natural Evolution Strategy, from the paper _"Novelty-Based Restarts for Evolution Strategies" (CEC2011)_. Check [here](https://exascale.info/members/giuseppe-cuccu/) for citation reference and pdf.
|
61
|
-
- **
|
61
|
+
- **DLR-VQ** stands for Decaying Learning Rate Vector Quantization, from the algorithm originally named _*Online VQ*_ in the paper _"Intrinsically Motivated Neuroevolution for Vision-Based Reinforcement Learning" (ICDL2011)_. Check [here](https://exascale.info/members/giuseppe-cuccu/) for citation reference and pdf.
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module MachineLearningWorkbench::Compressor
|
2
|
+
# Train-less VQ, copying new images into centroids
|
3
|
+
# Optimized for online training.
|
4
|
+
class CopyVQ < VectorQuantization
|
5
|
+
|
6
|
+
attr_reader :equal_simil, :next_train
|
7
|
+
|
8
|
+
def initialize **opts
|
9
|
+
puts "Ignoring learning rate: `lrate: #{opts[:lrate]}`" if opts[:lrate]
|
10
|
+
puts "Ignoring similarity: `simil_type: #{opts[:simil_type]}`" if opts[:simil_type]
|
11
|
+
# TODO: try different epsilons to reduce the number of states
|
12
|
+
# for example, in qbert we care what is lit and what is not, not the colors
|
13
|
+
@equal_simil = opts.delete(:equal_simil) || 0.0
|
14
|
+
super **opts.merge({lrate: nil, simil_type: nil})
|
15
|
+
@ntrains << 0 # to count duplicates, images we skip the train on
|
16
|
+
@next_train = 0 # pointer to the next centroid to train
|
17
|
+
end
|
18
|
+
|
19
|
+
def ntrains; @ntrains[0...-1]; end
|
20
|
+
def ntrains_skip; @ntrains.last; end
|
21
|
+
|
22
|
+
# Overloading lrate check from original VQ
|
23
|
+
def check_lrate lrate; nil; end
|
24
|
+
|
25
|
+
# Train on one vector:
|
26
|
+
# - train only if the image is not already in dictionary
|
27
|
+
# - find the next untrained centroid
|
28
|
+
# - training is just overwriting it
|
29
|
+
# @return [Integer] index of trained centroid
|
30
|
+
def train_one vec, eps: equal_simil
|
31
|
+
mses = centrs.map do |centr|
|
32
|
+
((centr-vec)**2).sum / centr.size
|
33
|
+
end
|
34
|
+
# BEWARE: I am currently not handling the case where we run out of centroids!
|
35
|
+
# => Will be addressed directly by dynamic dictionary size
|
36
|
+
# return -1 if mses.min < eps
|
37
|
+
return -1 if mses.min < eps || next_train == ncentrs
|
38
|
+
trg_idx = next_train
|
39
|
+
@next_train += 1
|
40
|
+
# require 'pry'; binding.pry if next_train == ncentrs
|
41
|
+
puts "Overwriting centr #{next_train}"
|
42
|
+
centrs[trg_idx] = vec
|
43
|
+
trg_idx
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module MachineLearningWorkbench::Compressor
|
2
|
-
#
|
2
|
+
# VQ with per-centroid decaying learning rates.
|
3
3
|
# Optimized for online training.
|
4
|
-
class
|
4
|
+
class DecayingLearningRateVQ < VectorQuantization
|
5
5
|
|
6
6
|
attr_reader :lrate_min, :lrate_min_den, :decay_rate
|
7
7
|
|
@@ -2,17 +2,20 @@ module MachineLearningWorkbench::Compressor
|
|
2
2
|
|
3
3
|
# Standard Vector Quantization
|
4
4
|
class VectorQuantization
|
5
|
-
attr_reader :ncentrs, :centrs, :dims, :vrange, :init_centr_vrange, :lrate,
|
6
|
-
|
5
|
+
attr_reader :ncentrs, :centrs, :dims, :vrange, :init_centr_vrange, :lrate,
|
6
|
+
:simil_type, :encoding_type, :rng, :ntrains, :utility, :ncodes
|
7
|
+
attr_writer :utility, :ncodes # allows access from outside
|
8
|
+
|
9
|
+
def initialize ncentrs:, dims:, vrange:, lrate:, simil_type: nil, encoding_type: nil, init_centr_vrange: nil, rseed: Random.new_seed
|
10
|
+
|
11
|
+
@rng = Random.new rseed # TODO: RNG CURRENTLY NOT USED!!
|
7
12
|
|
8
|
-
def initialize ncentrs:, dims:, vrange:, lrate:, simil_type: nil, init_centr_vrange: nil, rseed: Random.new_seed
|
9
|
-
# TODO: RNG CURRENTLY NOT USED!!
|
10
|
-
@rng = Random.new rseed
|
11
13
|
@ncentrs = ncentrs
|
12
14
|
@dims = Array(dims)
|
13
|
-
check_lrate lrate # hack: so that we can overload it in
|
15
|
+
check_lrate lrate # hack: so that we can overload it in dlr_vq
|
14
16
|
@lrate = lrate
|
15
17
|
@simil_type = simil_type || :dot
|
18
|
+
@encoding_type = encoding_type || :ensemble_norm
|
16
19
|
@init_centr_vrange ||= vrange
|
17
20
|
@vrange = case vrange
|
18
21
|
when Array
|
@@ -24,10 +27,12 @@ module MachineLearningWorkbench::Compressor
|
|
24
27
|
end
|
25
28
|
init_centrs
|
26
29
|
@ntrains = [0]*ncentrs # useful to understand what happens
|
30
|
+
@utility = NArray.zeros [ncentrs] # trace how 'useful' are centroids to encodings
|
31
|
+
@ncodes = 0
|
27
32
|
end
|
28
33
|
|
29
34
|
# Verify lrate to be present and withing unit bounds
|
30
|
-
# As a separate method only so it can be overloaded in `
|
35
|
+
# As a separate method only so it can be overloaded in `DecayingLearningRateVQ`
|
31
36
|
def check_lrate lrate
|
32
37
|
raise ArgumentError, "Pass a `lrate` between 0 and 1" unless lrate&.between?(0,1)
|
33
38
|
end
|
@@ -57,30 +62,45 @@ module MachineLearningWorkbench::Compressor
|
|
57
62
|
# Computes similarities between vector and all centroids
|
58
63
|
def similarities vec, type: simil_type
|
59
64
|
raise NotImplementedError if vec.shape.size > 1
|
60
|
-
|
65
|
+
simil_fn = SIMIL[type] || raise(ArgumentError, "Unrecognized simil #{type}")
|
66
|
+
NArray[*centrs.map { |centr| simil_fn.call centr, vec }]
|
61
67
|
# require 'parallel'
|
62
|
-
# Parallel.map(centrs) { |c| c.dot(vec).first }
|
68
|
+
# NArray[*Parallel.map(centrs) { |c| c.dot(vec).first }]
|
63
69
|
end
|
64
70
|
|
65
71
|
# Encode a vector
|
66
|
-
#
|
67
|
-
|
72
|
+
# tracks utility of centroids based on how much they contribute to encoding
|
73
|
+
# TODO: `encode = Encodings.const_get(type)` in initialize`
|
74
|
+
# NOTE: hashes of lambdas or modules cannot access ncodes and utility
|
75
|
+
def encode vec, type: encoding_type
|
68
76
|
simils = similarities vec
|
69
77
|
case type
|
70
78
|
when :most_similar
|
71
|
-
|
79
|
+
code = simils.max_index
|
80
|
+
@ncodes += 1
|
81
|
+
@utility[code] += 1
|
82
|
+
code
|
72
83
|
when :ensemble
|
73
|
-
simils
|
84
|
+
code = simils
|
85
|
+
tot = simils.sum
|
86
|
+
tot = 1 if tot < 1e-5 # HACK: avoid division by zero
|
87
|
+
contrib = code / tot
|
88
|
+
@ncodes += 1
|
89
|
+
@utility += (contrib - utility) / ncodes # cumulative moving average
|
90
|
+
code
|
74
91
|
when :ensemble_norm
|
75
|
-
tot = simils.
|
76
|
-
tot = 1 if tot
|
77
|
-
|
78
|
-
|
92
|
+
tot = simils.sum
|
93
|
+
tot = 1 if tot < 1e-5 # HACK: avoid division by zero
|
94
|
+
code = simils / tot
|
95
|
+
@ncodes += 1
|
96
|
+
@utility += (code - utility) / ncodes # cumulative moving average
|
97
|
+
code
|
98
|
+
else raise ArgumentError, "Unrecognized encode #{type}"
|
79
99
|
end
|
80
100
|
end
|
81
101
|
|
82
102
|
# Reconstruct vector from its code (encoding)
|
83
|
-
def reconstruction code, type:
|
103
|
+
def reconstruction code, type: encoding_type
|
84
104
|
case type
|
85
105
|
when :most_similar
|
86
106
|
centrs[code]
|
@@ -98,14 +118,13 @@ module MachineLearningWorkbench::Compressor
|
|
98
118
|
# followed by the corresponding similarity
|
99
119
|
def most_similar_centr vec
|
100
120
|
simils = similarities vec
|
101
|
-
|
102
|
-
max_idx
|
103
|
-
[max_idx, max_simil]
|
121
|
+
max_idx = simils.max_index
|
122
|
+
[max_idx, simils[max_idx]]
|
104
123
|
end
|
105
124
|
|
106
125
|
# Per-pixel errors in reconstructing vector
|
107
126
|
# @return [NArray] residuals
|
108
|
-
def reconstr_error vec, code: nil, type:
|
127
|
+
def reconstr_error vec, code: nil, type: encoding_type
|
109
128
|
code ||= encode vec, type: type
|
110
129
|
(vec - reconstruction(code, type: type)).abs.sum
|
111
130
|
end
|
@@ -129,7 +148,7 @@ module MachineLearningWorkbench::Compressor
|
|
129
148
|
vec_lst.each_with_index do |vec, i|
|
130
149
|
trained_idx = train_one vec
|
131
150
|
print '.' if debug
|
132
|
-
ntrains[trained_idx] += 1
|
151
|
+
@ntrains[trained_idx] += 1
|
133
152
|
end
|
134
153
|
end
|
135
154
|
end
|
@@ -162,31 +162,23 @@ module MachineLearningWorkbench::NeuralNetwork
|
|
162
162
|
|
163
163
|
## Activation functions
|
164
164
|
|
165
|
-
# Traditional sigmoid with variable steepness
|
165
|
+
# Traditional sigmoid (logistic) with variable steepness
|
166
166
|
def sigmoid k=0.5
|
167
167
|
# k is steepness: 0<k<1 is flatter, 1<k is flatter
|
168
168
|
# flatter makes activation less sensitive, better with large number of inputs
|
169
|
-
-> (
|
170
|
-
end
|
171
|
-
|
172
|
-
# Traditional logistic
|
173
|
-
def logistic
|
174
|
-
-> (x) do
|
175
|
-
exp = NMath.exp(x)
|
176
|
-
# exp.infinite? ? exp : exp / (1.0 + exp)
|
177
|
-
exp / (1.0 + exp)
|
178
|
-
end
|
169
|
+
-> (vec) { 1.0 / (NMath.exp(-k * vec) + 1.0) }
|
179
170
|
end
|
171
|
+
alias logistic sigmoid
|
180
172
|
|
181
173
|
# LeCun hyperbolic activation
|
182
174
|
# @see http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf Section 4.4
|
183
175
|
def lecun_hyperbolic
|
184
|
-
-> (
|
176
|
+
-> (vec) { 1.7159 * NMath.tanh(2.0*vec/3.0) + 1e-3*vec }
|
185
177
|
end
|
186
178
|
|
187
179
|
# Rectified Linear Unit (ReLU)
|
188
180
|
def relu
|
189
|
-
-> (
|
181
|
+
-> (vec) { (vec>0).all? && vec || vec.class.zeros(vec.shape) }
|
190
182
|
end
|
191
183
|
|
192
184
|
|
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
|
+
version: 0.6.0
|
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-04-
|
11
|
+
date: 2018-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -202,7 +202,8 @@ files:
|
|
202
202
|
- examples/neuroevolution.rb
|
203
203
|
- lib/machine_learning_workbench.rb
|
204
204
|
- lib/machine_learning_workbench/compressor.rb
|
205
|
-
- lib/machine_learning_workbench/compressor/
|
205
|
+
- lib/machine_learning_workbench/compressor/copy_vq.rb
|
206
|
+
- lib/machine_learning_workbench/compressor/decaying_learning_rate_vq.rb
|
206
207
|
- lib/machine_learning_workbench/compressor/vector_quantization.rb
|
207
208
|
- lib/machine_learning_workbench/monkey.rb
|
208
209
|
- lib/machine_learning_workbench/neural_network.rb
|