machine_learning_workbench 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +15 -0
  3. data/.gitignore +11 -0
  4. data/.rspec +3 -0
  5. data/.travis.yml +5 -0
  6. data/Gemfile +6 -0
  7. data/Gemfile.lock +70 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +37 -0
  10. data/Rakefile +6 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/lib/machine_learning_workbench.rb +19 -0
  14. data/lib/machine_learning_workbench/compressor.rb +1 -0
  15. data/lib/machine_learning_workbench/compressor/vector_quantization.rb +74 -0
  16. data/lib/machine_learning_workbench/monkey.rb +197 -0
  17. data/lib/machine_learning_workbench/neural_network.rb +3 -0
  18. data/lib/machine_learning_workbench/neural_network/base.rb +211 -0
  19. data/lib/machine_learning_workbench/neural_network/feed_forward.rb +20 -0
  20. data/lib/machine_learning_workbench/neural_network/recurrent.rb +35 -0
  21. data/lib/machine_learning_workbench/optimizer.rb +7 -0
  22. data/lib/machine_learning_workbench/optimizer/natural_evolution_strategies/base.rb +112 -0
  23. data/lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb +104 -0
  24. data/lib/machine_learning_workbench/optimizer/natural_evolution_strategies/snes.rb +40 -0
  25. data/lib/machine_learning_workbench/optimizer/natural_evolution_strategies/xnes.rb +46 -0
  26. data/lib/machine_learning_workbench/tools.rb +4 -0
  27. data/lib/machine_learning_workbench/tools/execution.rb +18 -0
  28. data/lib/machine_learning_workbench/tools/imaging.rb +48 -0
  29. data/lib/machine_learning_workbench/tools/normalization.rb +22 -0
  30. data/lib/machine_learning_workbench/tools/verification.rb +11 -0
  31. data/machine_learning_workbench.gemspec +36 -0
  32. metadata +216 -0
@@ -0,0 +1,40 @@
1
+
2
+ module MachineLearningWorkbench::Optimizer::NaturalEvolutionStrategies
3
+ # Separable Natural Evolution Strategies
4
+ class SNES < Base
5
+
6
+ attr_reader :variances
7
+
8
+ def initialize_distribution mu_init: 0, sigma_init: 1
9
+ @mu = NMatrix.new([1, ndims], mu_init, dtype: :float64)
10
+ sigma_init = [sigma_init]*ndims unless sigma_init.kind_of? Enumerable
11
+ @variances = NMatrix.new([1,ndims], sigma_init, dtype: :float64)
12
+ @sigma = NMatrix.diagonal(variances, dtype: :float64)
13
+ end
14
+
15
+ def train picks: sorted_inds
16
+ g_mu = utils.dot(picks)
17
+ g_sigma = utils.dot(picks**2 - 1)
18
+ @mu += sigma.dot(g_mu.transpose).transpose * lrate
19
+ @variances *= (g_sigma * lrate / 2).exponential
20
+ @sigma = NMatrix.diagonal(variances, dtype: :float64)
21
+ end
22
+
23
+ # Estimate algorithm convergence as total variance
24
+ def convergence
25
+ variances.reduce :+
26
+ end
27
+
28
+ def save
29
+ [mu.to_consistent_a, variances.to_consistent_a]
30
+ end
31
+
32
+ def load data
33
+ raise ArgumentError unless data.size == 2
34
+ mu_ary, variances_ary = data
35
+ @mu = NMatrix[*mu_ary, dtype: :float64]
36
+ @variances = NMatrix[*variances_ary, dtype: :float64]
37
+ @sigma = NMatrix.diagonal(variances, dtype: :float64)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,46 @@
1
+
2
+ module MachineLearningWorkbench::Optimizer::NaturalEvolutionStrategies
3
+ # Exponential Natural Evolution Strategies
4
+ class XNES < Base
5
+ attr_reader :log_sigma
6
+
7
+ def initialize_distribution mu_init: 0, sigma_init: 1
8
+ @mu = NMatrix.new([1, ndims], mu_init, dtype: :float64)
9
+ sigma_init = [sigma_init]*ndims unless sigma_init.kind_of? Enumerable
10
+ @sigma = NMatrix.diag(sigma_init, dtype: :float64)
11
+ # Works with the log of sigma to avoid continuous decompositions (thanks Sun Yi)
12
+ log_sigma_init = sigma_init.map &Math.method(:log)
13
+ @log_sigma = NMatrix.diag(log_sigma_init, dtype: :float64)
14
+ end
15
+
16
+ def train picks: sorted_inds
17
+ g_mu = utils.dot(picks)
18
+ g_log_sigma = popsize.times.inject(NMatrix.zeros_like sigma) do |sum, i|
19
+ u = utils[i]
20
+ ind = picks.row(i)
21
+ ind_sq = ind.outer_flat(ind, &:*)
22
+ sum + (ind_sq - id) * u
23
+ end
24
+ @mu += sigma.dot(g_mu.transpose).transpose * lrate
25
+ @log_sigma += g_log_sigma * (lrate/2)
26
+ @sigma = log_sigma.exponential
27
+ end
28
+
29
+ # Estimate algorithm convergence as total variance
30
+ def convergence
31
+ sigma.trace
32
+ end
33
+
34
+ def save
35
+ [mu.to_consistent_a, log_sigma.to_consistent_a]
36
+ end
37
+
38
+ def load data
39
+ raise ArgumentError unless data.size == 2
40
+ mu_ary, log_sigma_ary = data
41
+ @mu = NMatrix[*mu_ary, dtype: :float64]
42
+ @log_sigma = NMatrix[*log_sigma_ary, dtype: :float64]
43
+ @sigma = log_sigma.exponential
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,4 @@
1
+ require_relative 'tools/execution'
2
+ require_relative 'tools/normalization'
3
+ require_relative 'tools/imaging'
4
+ require_relative 'tools/verification'
@@ -0,0 +1,18 @@
1
+ module MachineLearningWorkbench::Tools
2
+ module Execution
3
+ $fork_pids ||= []
4
+
5
+ # Execute block in a fork. Be sure to check also `#kill_forks`
6
+ def self.in_fork &block
7
+ raise ArgumentError "Need block to be executed in fork" unless block
8
+ pid = fork(&block)
9
+ Process.detach pid
10
+ $fork_pids << pid
11
+ end
12
+
13
+ # Call this in an `ensure` block after using `in_fork`
14
+ def self.kill_forks
15
+ $fork_pids&.each { |pid| Process.kill 'KILL', pid }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,48 @@
1
+ module MachineLearningWorkbench::Tools
2
+ module Imaging
3
+ Forkable = MachineLearningWorkbench::Tools::Execution
4
+ Norm = MachineLearningWorkbench::Tools::Normalization
5
+
6
+ # Create RMagick::Image from NMatrix data
7
+ def self.nmat_to_img nmat, shape: nil
8
+ shape ||= nmat.shape
9
+ shape = [1, shape] if shape.kind_of?(Integer) || shape.size == 1
10
+ # `Image::constitute` requires Float pixels to be in [0,1]
11
+ pixels = Norm.feature_scaling nmat.round(4), to: [0,1]
12
+ Magick::Image.constitute *shape, "I", pixels.to_flat_a
13
+ end
14
+
15
+ # Create PNG file from NMatrix data
16
+ def self.nmat_to_png nmat, fname, shape: nil
17
+ nmat_to_img(nmat, shape: shape).write fname
18
+ end
19
+
20
+ # Show a NMatrix as image in a RMagick window
21
+ # @param disp_size the size of the image to display
22
+ # @param shape the true shape of the image (NMatrix could be flattened)
23
+ # @param in_fork [bool] whether to execute the display in fork (and continue running)
24
+ def self.display nmat, disp_size: [300, 300], shape: nil, in_fork: true
25
+ img = nmat_to_img(nmat, shape: shape).resize(*disp_size)
26
+ if in_fork
27
+ MachineLearningWorkbench::Tools::Execution.in_fork { img.display }
28
+ else
29
+ img.display
30
+ end
31
+ end
32
+
33
+ # Create NMatrix from png by filename.
34
+ # @param fname the file name
35
+ # @param scale optional rescaling of the image
36
+ # @param flat [bool] whether to return a flat array
37
+ # @param dtype dtype for the NMatrix, leave `nil` for automatic detection
38
+ def self.nmat_from_png fname, scale: nil, flat: false, dtype: nil
39
+ img = Magick::ImageList.new(fname).first
40
+ img.scale!(scale) if scale
41
+ shape = [img.columns, img.rows]
42
+ pixels = img.export_pixels(0, 0, *shape, 'I') # 'I' for intensity
43
+ raise "Sanity check" unless shape.reduce(:*)==pixels.size
44
+ return pixels.to_nm(nil, dtype) if flat
45
+ NMatrix.new shape, pixels, dtype: dtype
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,22 @@
1
+ module MachineLearningWorkbench::Tools
2
+ module Normalization
3
+ def self.feature_scaling nmat, from: nil, to: [0,1]
4
+ from ||= nmat.minmax
5
+ old_min, old_max = from
6
+ new_min, new_max = to
7
+ res = (nmat-old_min)*(new_max-new_min)/(old_max-old_min)+new_min
8
+ end
9
+
10
+ # @param per_column [bool] wheather to compute stats per-column or matrix-wise
11
+ def self.z_score nmat, per_column: true
12
+ raise NotImplementedError unless per_column
13
+ means = nmat.mean
14
+ stddevs = nmat.std
15
+ # address edge case of zero variance
16
+ stddevs.map! { |v| v.zero? ? 1 : v }
17
+ mean_mat = means.repeat nmat.rows, 0
18
+ stddev_mat = stddevs.repeat nmat.rows, 0
19
+ ret = (nmat - mean_mat) / stddev_mat
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ module MachineLearningWorkbench::Tools
2
+ module Verification
3
+ def self.in_range! nmat, vrange
4
+ vmin, vmax = vrange.to_a
5
+ nmat.each_with_indices do |v, *idxs|
6
+ nmat[*idxs] = vmin if v < vmin
7
+ nmat[*idxs] = vmax if v > vmax
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,36 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "machine_learning_workbench"
7
+ spec.version = `git describe`
8
+ spec.authors = ["Giuseppe Cuccu"]
9
+ spec.email = ["giuseppe.cuccu@gmail.com"]
10
+
11
+ spec.summary = %q{Workbench for practical machine learning in Ruby.}
12
+ spec.description = %q{This workbench holds a collection of machine learning methods in Ruby. Rather than specializing on a single task or method, this gem aims at providing an encompassing framework for any machine learning application.}
13
+ spec.homepage = "https://github.com/giuse/machine_learning_workbench"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_dependency "nmatrix-atlas", "~> 0.2"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.16"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "rspec", "~> 3.0"
28
+ spec.add_development_dependency "pry", "~> 0.10"
29
+ spec.add_development_dependency "pry-nav", "~> 0.2"
30
+ spec.add_development_dependency "pry-rescue", "~> 1.4"
31
+ spec.add_development_dependency "pry-stack_explorer", "~> 0.4"
32
+
33
+ # currently under trial
34
+ spec.add_development_dependency "rmagick"
35
+ spec.add_development_dependency "parallel"
36
+ end
metadata ADDED
@@ -0,0 +1,216 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: machine_learning_workbench
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Giuseppe Cuccu
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-03-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nmatrix-atlas
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.16'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.16'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.10'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.10'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry-nav
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.2'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry-rescue
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.4'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.4'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry-stack_explorer
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.4'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.4'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rmagick
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: parallel
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: This workbench holds a collection of machine learning methods in Ruby.
154
+ Rather than specializing on a single task or method, this gem aims at providing
155
+ an encompassing framework for any machine learning application.
156
+ email:
157
+ - giuseppe.cuccu@gmail.com
158
+ executables: []
159
+ extensions: []
160
+ extra_rdoc_files: []
161
+ files:
162
+ - ".codeclimate.yml"
163
+ - ".gitignore"
164
+ - ".rspec"
165
+ - ".travis.yml"
166
+ - Gemfile
167
+ - Gemfile.lock
168
+ - LICENSE.txt
169
+ - README.md
170
+ - Rakefile
171
+ - bin/console
172
+ - bin/setup
173
+ - lib/machine_learning_workbench.rb
174
+ - lib/machine_learning_workbench/compressor.rb
175
+ - lib/machine_learning_workbench/compressor/vector_quantization.rb
176
+ - lib/machine_learning_workbench/monkey.rb
177
+ - lib/machine_learning_workbench/neural_network.rb
178
+ - lib/machine_learning_workbench/neural_network/base.rb
179
+ - lib/machine_learning_workbench/neural_network/feed_forward.rb
180
+ - lib/machine_learning_workbench/neural_network/recurrent.rb
181
+ - lib/machine_learning_workbench/optimizer.rb
182
+ - lib/machine_learning_workbench/optimizer/natural_evolution_strategies/base.rb
183
+ - lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb
184
+ - lib/machine_learning_workbench/optimizer/natural_evolution_strategies/snes.rb
185
+ - lib/machine_learning_workbench/optimizer/natural_evolution_strategies/xnes.rb
186
+ - lib/machine_learning_workbench/tools.rb
187
+ - lib/machine_learning_workbench/tools/execution.rb
188
+ - lib/machine_learning_workbench/tools/imaging.rb
189
+ - lib/machine_learning_workbench/tools/normalization.rb
190
+ - lib/machine_learning_workbench/tools/verification.rb
191
+ - machine_learning_workbench.gemspec
192
+ homepage: https://github.com/giuse/machine_learning_workbench
193
+ licenses:
194
+ - MIT
195
+ metadata: {}
196
+ post_install_message:
197
+ rdoc_options: []
198
+ require_paths:
199
+ - lib
200
+ required_ruby_version: !ruby/object:Gem::Requirement
201
+ requirements:
202
+ - - ">="
203
+ - !ruby/object:Gem::Version
204
+ version: '0'
205
+ required_rubygems_version: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - ">="
208
+ - !ruby/object:Gem::Version
209
+ version: '0'
210
+ requirements: []
211
+ rubyforge_project:
212
+ rubygems_version: 2.6.11
213
+ signing_key:
214
+ specification_version: 4
215
+ summary: Workbench for practical machine learning in Ruby.
216
+ test_files: []