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
-
#blocks ⇒ Object
readonly
Returns the value of attribute blocks.
-
#ndims_lst ⇒ Object
readonly
Returns the value of attribute ndims_lst.
-
#popsize ⇒ Object
readonly
Returns the value of attribute popsize.
Attributes inherited from Base
#best, #eye, #last_fits, #ndims, #obj_fn, #opt_type, #parallel_fit, #rescale_lrate, #rescale_popsize, #rng, #sigma
Instance Method Summary collapse
- #convergence ⇒ Object
-
#initialize(ndims_lst, obj_fn, opt_type, parallel_fit: false, rseed: nil, **init_opts) ⇒ BDNES
constructor
Initialize a list of XNES, one for each block see class ‘Base` for the description of the rest of the arguments.
- #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, parallel_fit: false, rseed: nil, **init_opts) ⇒ BDNES
Initialize a list of XNES, one for each block see class ‘Base` for the description of the rest of the arguments.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 16 def initialize ndims_lst, obj_fn, opt_type, parallel_fit: false, 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, @parallel_fit = ndims_lst, obj_fn, opt_type, parallel_fit 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
#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 |
#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 |
#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 |
Instance Method Details
#convergence ⇒ Object
95 96 97 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 95 def convergence blocks.map(&:convergence).reduce(:+) end |
#load(data) ⇒ Object
103 104 105 106 107 108 109 110 111 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 103 def load data 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
91 92 93 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 91 def mu blocks.map(&:mu).reduce { |mem, var| mem.concatenate var, axis: 1 } end |
#save ⇒ Object
99 100 101 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 99 def save blocks.map &:save end |
#sorted_inds_lst ⇒ Object
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 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 39 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 { |mem, var| mem.concatenate var, axis: 1 } # Need to fix sample 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 = parallel_fit ? obj_fn.call(full_inds) : full_inds.map(&obj_fn) # 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) sort_idxs = fits.sort_index sort_idxs = sort_idxs.reverse if opt_type == :min this_best = [fits[sort_idxs[-1]], full_inds[sort_idxs[-1], true]] opt_cmp_fn = opt_type==:min ? :< : :> @best = this_best if this_best.first.send(opt_cmp_fn, best.first) sorted_samples = full_samples.values_at *sort_idxs # 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 NArray for usage in training block_samples.map &:to_na end |
#train(picks: sorted_inds_lst) ⇒ Object
duck-type the interface: [:train, :mu, :convergence, :save, :load]
85 86 87 88 89 |
# File 'lib/machine_learning_workbench/optimizer/natural_evolution_strategies/bdnes.rb', line 85 def train picks: sorted_inds_lst blocks.zip(sorted_inds_lst).each do |xnes, s_inds| xnes.train picks: s_inds end end |