machine_learning_workbench 0.5.1 → 0.6.0

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
  SHA1:
3
- metadata.gz: afdd4f1bf99c2abbe10f4c348531f4efabde3c73
4
- data.tar.gz: 2334e9b7e5c4f276f94e75dd50164f8fa78cc699
3
+ metadata.gz: 0677a5bd2af361c57794f13c2c62ceb353bab987
4
+ data.tar.gz: 160f5d7f06abc3c4520a7753cd4fa0f155bbb09e
5
5
  SHA512:
6
- metadata.gz: 4f51ca6077627401bb1c27dfaed60cb84e5d70bdebe2f7c6d366abae299040e32ec7a4a1ad1ee3dc8ccc9aaa536a4125e91c2e97eaf043115d21e5e41d6a8e70
7
- data.tar.gz: 884493c20fde5e8ac707f6c00b442d924a7dab5d783cf011926c2425b92116eea2bd1f10116a026b9b55db2210d918aa533eb0a6bc259b7bd0704df217b0985b
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
- - **Online VQ** stands for Online Vector Quantization, 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.
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.
@@ -1,2 +1,3 @@
1
1
  require_relative 'compressor/vector_quantization'
2
- require_relative 'compressor/online_vector_quantization'
2
+ require_relative 'compressor/decaying_learning_rate_vq'
3
+ require_relative 'compressor/copy_vq'
@@ -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
- # Online Vector Quantization: VQ with per-centroid decaying learning rates.
2
+ # VQ with per-centroid decaying learning rates.
3
3
  # Optimized for online training.
4
- class OnlineVectorQuantization < VectorQuantization
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, :simil_type, :rng, :ntrains
6
- Verification = MachineLearningWorkbench::Tools::Verification
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 online_vq
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 `OnlineVectorQuantization`
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
- centrs.map { |centr| SIMIL[type].call centr, vec }
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
- # TODO: optimize for Numo
67
- def encode vec, type: :most_similar
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
- simils.index simils.max
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.reduce(:+)
76
- tot = 1 if tot == 0 # HACK: avoid division by zero
77
- simils.map { |s| s/tot }
78
- else raise ArgumentError, "unrecognized encode type: #{type}"
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: :most_similar
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
- max_simil = simils.max
102
- max_idx = simils.index max_simil
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: :most_similar
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
- -> (x) { 1.0 / (NMath.exp(-k * x) + 1.0) }
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
- -> (x) { 1.7159 * NMath.tanh(2.0*x/3.0) + 1e-3*x }
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
- -> (x) { (x>0).all? && x || x.class.zeros(x.shape) }
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.5.1
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-06 00:00:00.000000000 Z
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/online_vector_quantization.rb
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