Class: MachineLearningWorkbench::Optimizer::NaturalEvolutionStrategies::BDNES
- Inherits:
-
Base
- Object
- Base
- MachineLearningWorkbench::Optimizer::NaturalEvolutionStrategies::BDNES
- Defined in:
- lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb
Overview
Block-Diagonal Natural Evolution Strategies
Constant Summary collapse
- MAX_RSEED =
same range as Random.new_seed
10**Random.new_seed.size
Instance Attribute Summary collapse
-
#best ⇒ Object
readonly
Returns the value of attribute best.
-
#blocks ⇒ Object
readonly
Returns the value of attribute blocks.
-
#last_fits ⇒ Object
readonly
Returns the value of attribute last_fits.
-
#ndims_lst ⇒ Object
readonly
Returns the value of attribute ndims_lst.
-
#obj_fn ⇒ Object
readonly
Returns the value of attribute obj_fn.
-
#opt_type ⇒ Object
readonly
Returns the value of attribute opt_type.
-
#popsize ⇒ Object
readonly
Returns the value of attribute popsize.
-
#rng ⇒ Object
readonly
Returns the value of attribute rng.
Attributes inherited from Base
Instance Method Summary collapse
- #convergence ⇒ Object
-
#initialize(ndims_lst, obj_fn, opt_type, rseed: nil, **init_opts) ⇒ BDNES
constructor
initialize a list of XNES for each block.
- #load(data) ⇒ Object
- #mu ⇒ Object
- #save ⇒ Object
- #sorted_inds_lst ⇒ Object
-
#train(picks: sorted_inds_lst) ⇒ Object
duck-type the interface: [:train, :mu, :convergence, :save, :load].
Methods inherited from Base
#cmaes_lrate, #cmaes_popsize, #cmaes_utilities, #interface_methods, #lrate, #move_inds, #sorted_inds, #standard_normal_sample, #standard_normal_samples, #utils
Constructor Details
#initialize(ndims_lst, obj_fn, opt_type, rseed: nil, **init_opts) ⇒ BDNES
initialize a list of XNES for each block
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 12 def initialize ndims_lst, obj_fn, opt_type, rseed: nil, **init_opts # mu_init: 0, sigma_init: 1 # init_opts = {rseed: rseed, mu_init: mu_init, sigma_init: sigma_init} # TODO: accept list of `mu_init`s and `sigma_init`s @ndims_lst, @obj_fn, @opt_type = ndims_lst, obj_fn, opt_type block_fit = -> (*args) { raise "Should never be called" } # the BD-NES seed should ensure deterministic reproducibility # but each block should have a different seed rseed ||= Random.new_seed # puts "BD-NES rseed: #{s}" # currently disabled @rng = Random.new rseed @blocks = ndims_lst.map do |ndims| b_rseed = rng.rand MAX_RSEED XNES.new ndims, block_fit, opt_type, rseed: b_rseed, **init_opts end # Need `popsize` to be the same for all blocks, to make complete individuals @popsize = blocks.map(&:popsize).max blocks.each { |xnes| xnes.instance_variable_set :@popsize, popsize } @best = [(opt_type==:max ? -1 : 1) * Float::INFINITY, nil] @last_fits = [] end |
Instance Attribute Details
#best ⇒ Object (readonly)
Returns the value of attribute best.
8 9 10 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 8 def best @best end |
#blocks ⇒ Object (readonly)
Returns the value of attribute blocks.
8 9 10 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 8 def blocks @blocks end |
#last_fits ⇒ Object (readonly)
Returns the value of attribute last_fits.
8 9 10 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 8 def last_fits @last_fits end |
#ndims_lst ⇒ Object (readonly)
Returns the value of attribute ndims_lst.
8 9 10 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 8 def ndims_lst @ndims_lst end |
#obj_fn ⇒ Object (readonly)
Returns the value of attribute obj_fn.
8 9 10 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 8 def obj_fn @obj_fn end |
#opt_type ⇒ Object (readonly)
Returns the value of attribute opt_type.
8 9 10 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 8 def opt_type @opt_type end |
#popsize ⇒ Object (readonly)
Returns the value of attribute popsize.
8 9 10 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 8 def popsize @popsize end |
#rng ⇒ Object (readonly)
Returns the value of attribute rng.
8 9 10 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 8 def rng @rng end |
Instance Method Details
#convergence ⇒ Object
85 86 87 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 85 def convergence blocks.map(&:convergence).reduce(:+) end |
#load(data) ⇒ Object
93 94 95 96 97 98 99 100 101 102 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 93 def load data # raise "Hell!" unless data.size == 2 fit = -> (*args) { raise "Should never be called" } @blocks = data.map do |block_data| ndims = block_data.first.size XNES.new(ndims, fit, opt_type).tap do |nes| nes.load block_data end end end |
#mu ⇒ Object
81 82 83 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 81 def mu blocks.map(&:mu).reduce(&:hconcat) end |
#save ⇒ Object
89 90 91 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 89 def save blocks.map &:save end |
#sorted_inds_lst ⇒ Object
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 35 def sorted_inds_lst # Build samples and inds from the list of blocks samples_lst, inds_lst = blocks.map do |xnes| samples = xnes.standard_normal_samples inds = xnes.move_inds(samples) [samples.to_a, inds] end.transpose # Join the individuals for evaluation full_inds = inds_lst.reduce(&:hconcat).to_a # Need to fix samples dimensions for sorting # - current dims: nblocks x ninds x [block sizes] # - for sorting: ninds x nblocks x [block sizes] full_samples = samples_lst.transpose # Evaluate fitness of complete individuals fits = obj_fn.call(full_inds) # Quick cure for NaN fitnesses fits.map! { |x| x.nan? ? (opt_type==:max ? -1 : 1) * Float::INFINITY : x } @last_fits = fits # allows checking for stagnation # Sort inds based on fit and opt_type, save best sorted = [fits, full_inds, full_samples].transpose.sort_by(&:first) sorted.reverse! if opt_type==:min this_best = sorted.last.take(2) opt_cmp_fn = opt_type==:min ? :< : :> @best = this_best if this_best.first.send(opt_cmp_fn, best.first) sorted_samples = sorted.map(&:last) # Need to bring back sample dimensions for each block # - current dims: ninds x nblocks x [block sizes] # - target blocks list: nblocks x ninds x [block sizes] block_samples = sorted_samples.transpose # then back to NMatrix for usage in training block_samples.map { |sample| NMatrix[*sample, dtype: :float64] } end |
#train(picks: sorted_inds_lst) ⇒ Object
duck-type the interface: [:train, :mu, :convergence, :save, :load]
75 76 77 78 79 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 75 def train picks: sorted_inds_lst blocks.zip(sorted_inds_lst).each do |xnes, s_inds| xnes.train picks: s_inds end end |