JuliaAI / MLJTuning.jl

Hyperparameter optimization algorithms for use in the MLJ machine learning framework
MIT License
66 stars 12 forks source link

Add a model buffer to save surplus models generated by `models` #131

Closed ablaom closed 3 years ago

ablaom commented 3 years ago

Currently when models generates more models than required (because including them would increase the history length beyond the number of iterations n specified at TunedModel construction) the surplus models are simply dropped. This leads to wrong behaviour in a "warm-restart" of tuning.

This PR adds a "model buffer" to fix this behaviour. It also modifies the Grid implementation which was working before, but for the "wrong reasons". I don't think any other current strategies are actually effected by the bug but a discussion with @lhnguyen-vn on PSO made me realize the potential for future problems.

I'm including below a relevant section of the updated README for further clarification:


The models method: For generating model batches to evaluate

MLJTuning.models(tuning::MyTuningStrategy, model, history, state, n_remaining, verbosity)
    -> vector_of_models, new_state

This is the core method of a new implementation. Given the existing history and state, it must return a vector ("batch") of new model instances vector_of_models to be evaluated, and the updated state. Any number of models may be returned (and this includes an empty vector or nothing) and the evaluations will be performed in parallel (using the mode of parallelization defined by the acceleration field of the TunedModel instance).

If more models are returned than needed (because including them would   <---------- see here in particular create a history whose length exceeds the user-specified number of iterations tuned_model.n) then the surplus models are saved, for use in a "warm restart" of tuning, when the user increases tuned_model.n. The remaining models are then evaluated and these evaluations are added to the history. In any warm restart, no new call to models will be made until all saved models have been evaluated, and these evaluations added to the history.

If the tuning algorithm exhausts it's supply of new models (because, for example, there is only a finite supply, as in a Grid search) then vector_of_models should be an empty vector or nothing. The interface has no fixed "batch-size" parameter, and the tuning algorithm is happy to receive any number of models; a surplus is handled as explained above, a shortfall will trigger an early stop (so that the final history has length less than tuned_model.n).

If needed, extra metadata may be attached to each model returned; see below.

Sequential tuning strategies generating models non-deterministically (e.g., simulated annealing) might choose to include a batch size hyperparameter, and arrange that models returns batches of the specified size (to be evaluated in parallel when acceleration is set appropriately). However, the evaluations and history updates do not occur until after the models call, so it may be complicated or impossible to preserve the original (strictly) sequential algorithm in that case, which should be clearly documented.

Some simple tuning strategies, such as RandomSearch, will want to return as many models as possible in one hit. To this end, the variable n_remaining is passed to the models call; this is the difference between the current length of the history and tuned_model.n.

Including model metadata

If a tuning strategy implementation needs to record additional metadata in the history, for each model generated, then instead of model instances, vector_of_models should be vector of tuples of the form (m, metadata), where m is a model instance, and metadata the associated data. To access the metadata for the jth element of the existing history, use history[j].metadata.

codecov-commenter commented 3 years ago

Codecov Report

Merging #131 (75a5749) into dev (da9364b) will increase coverage by 0.34%. The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##              dev     #131      +/-   ##
==========================================
+ Coverage   86.60%   86.94%   +0.34%     
==========================================
  Files          11       11              
  Lines         575      590      +15     
==========================================
+ Hits          498      513      +15     
  Misses         77       77              
Impacted Files Coverage Δ
src/strategies/explicit.jl 92.00% <ø> (ø)
src/utilities.jl 100.00% <ø> (ø)
src/strategies/grid.jl 100.00% <100.00%> (ø)
src/tuned_models.jl 92.23% <100.00%> (+0.48%) :arrow_up:

Continue to review full report at Codecov.

Legend - Click here to learn more Δ = absolute <relative> (impact), ø = not affected, ? = missing data Powered by Codecov. Last update da9364b...75a5749. Read the comment docs.

ablaom commented 3 years ago

Also, the PR includes this clarification in the README.md: