What’s New in v0.5.0¶
The new version of pyribs is here! Much has changed since our last version, v0.4.0. Most of these changes can be categorized under two goals: (1) integrate new algorithms via new emitters and schedulers, and (2) improve archive performance via batched operations. We will review the changes related to these goals and several other changes made to pyribs. For the full list of changes, refer to our History page.
Note
To improve the pyribs API, many of these changes are backwards-incompatible and break existing v0.4.0 code. In the future, we anticipate that we will introduce fewer breaking changes as pyribs matures to have a clean, stable API.
General¶
We’ll start with some important general changes.
Tutorials¶
We’ve added new tutorials and expanded our old ones! We recommend going over the updated version of our introductory tutorial, Using CMA-ME to Land a Lunar Lander Like a Space Shuttle, to get a feel for the new API. Then, learn how we have integrated the CMA-MAE algorithm in Upgrading CMA-ME to CMA-MAE on the Sphere Benchmark, and implement Differentiable Quality Diversity (DQD) algorithms in the tutorial Generating Tom Cruise Images with DQD Algorithms.
Terminology¶
measures vs behaviors: We have adopted the
measures
terminology of recent literature over thebehaviors
terminology in pyribs 0.4.0. Names such asbehavior_values
are now referred to asmeasures
. While QD originated in neuroevolution with the purpose of producing diverse collections of agents, QD optimization has grown into a general-purpose optimization paradigm. For example, in an application where QD generates images of a face with varying age and hair length, it seems odd to refer to age and hair length as behaviors. Our new terminology instead refers to the age and hair length as measures of the solutions, where QD optimization must vary the outputs of those measures.Batch arguments: Many of our methods now operate in batch. The batch arguments are referred to as
solution_batch
,objective_batch
,measures_batch
, andmetadata_batch
, while individual arguments are referred to assolution
,objective
,measures
, andmetadata
.cells vs bins: For consistency with the literature, we have replaced the term
bins
withcells
when discussing archives.optimizers are now schedulers: To better reflect their role, the “optimizers” from pyribs v0.4.0 are now referred to as “schedulers”. All schedulers are under the
ribs.schedulers
module, includingScheduler
andBanditScheduler
.
Installation¶
There are now three distributions of pyribs, as shown in the table below. If you do not use ribs.visualize
, we recommend installing the default distribution with with pip install ribs
or conda install pyribs
. If you do use ribs.visualize
, you can install pyribs with pip install ribs[visualize]
or conda install pyribs-visualize
.
Name | PyPI Package | Conda Package | Description |
---|---|---|---|
Default |
|
| Basic pyribs package. |
Visualize |
|
| Adds visualization dependencies, currently just Matplotlib. |
All |
|
| Installs dependencies for all extra distributions (currently just the Visualize extra). |
Goal 1: Implement New Algorithms¶
Our first major goal in pyribs v0.5.0 has been to implement an array of new algorithms via new emitters and schedulers.
Flexible CMA-ME and CMA-MAE with EvolutionStrategyEmitter¶
We introduce the EvolutionStrategyEmitter
which replaces the earlier ImprovementEmitter
, RandomDirectionEmitter
, and OptimizingEmitter
. This emitter may be used in both CMA-ME and CMA-MAE. The behaviors of these earlier emitters may be replicated by selecting an appropriate ranker from the ribs.emitters.rankers
module. For example:
EvolutionStrategyEmitter(archive, ..., ranker="2imp") # Equivalent to ImprovementEmitter.
EvolutionStrategyEmitter(archive, ..., ranker="imp") # Single-stage improvement ranking as is used in CMA-MAE.
EvolutionStrategyEmitter(archive, ..., ranker="2rd") # Two-stage random direction ranking.
EvolutionStrategyEmitter(archive, ..., ranker="obj") # Objective ranking as was done in OptimizingEmitter.
EvolutionStrategyEmitter
also supports evolution strategies other than CMA-ES, thus enabling it to implement scalable variants of CMA-ME and CMA-MAE described in Tjanaka 2022. These evolution strategies are available in the ribs.emitters.opt
module. For example:
EvolutionStrategyEmitter(archive, ..., es="sep_cma_es") # sep-CMA-ES instead of CMA-ES.
DQD Algorithms with GradientArborescenceEmitter¶
We have added a GradientArborescenceEmitter
which supports DQD algorithms. For usage examples, see the tutorial Generating Tom Cruise Images with DQD Algorithms.
Custom Initial Solutions in Emitters¶
By default, on the first iteration (the first iteration is detected by checking that the archive is empty), both GaussianEmitter
and IsoLineEmitter
sample solutions from a Gaussian distribution. However, many implementations of MAP-Elites sample solutions from a uniform distribution on the first iteration. More generally, users may seek to provide any custom population of solutions for the first iteration.
Before, it was possible to provide custom initial solutions by evaluating the initial solutions and directly add()
’ing them to the archive, like so:
archive = ...
emitters = [GaussianEmitter(archive, ...)]
scheduler = Scheduler(archive, emitters)
initial_solutions = ...
objectives, measures = evaluate(initial_solutions)
archive.add(initial_solutions, objectives, measures)
for itr in range(1000):
...
However, it can be inconvenient to have to add this special case before the main pyribs loop, e.g., if the evaluation function is more complex than a single line. Thus, we now make it possible to pass the initial solutions to the emitters so that on the first iteration of the QD algorithm (more specifically, when the archive is empty), these initial solutions are returned.
archive = ...
emitters = [GaussianEmitter(archive, ..., initial_solutions=[[0.0, 1.0], [1.3, 2.0]])]
scheduler = Scheduler(archive, emitters)
for itr in range(1000):
# On the first iteration, `solutions` will be the `initial_solutions` that
# were passed into GaussianEmitter.
solutions = scheduler.ask()
ME-MAP-Elites with BanditScheduler¶
We have added a new BanditScheduler
which maintains a pool of emitters and only asks a subset of emitters for solutions on each iteration. The emitters to ask are selected with a multi-armed bandit algorithm. This scheduler is our implementation of the ME-MAP-Elites algorithm.
Goal 2: Improve Archive Performance via Batching¶
Before, pyribs archives operated on solutions one at a time. Now, most archives (with the exception of SlidingBoundariesArchive) improve performance by relying on batch operations.
New Archive Methods¶
The following table shows the old methods and the names of the new methods which operate on batched inputs. As a convenience, we have also included “single” methods which can operate on single inputs.
Old Method | New Batched Method | New Single Method |
---|---|---|
| ||
| ||
| N/A | |
|
To elaborate on these changes:
All archive indices must now be integers (before, indices could be tuples of integers). Thus, the
get_index()
method has been replaced withindex_of()
, which takes in a batch of measures (i.e. a(batch_size, measure_dim)
array) and returns a batch of integer indices. Furthermore, whereasArchiveBase
used to take in astorage_dims
argument, it now takes in a singlestorage_dim
argument because indices are all integers.Since grid indices have meaning in
GridArchive
andSlidingBoundariesArchive
, we have also added agrid_to_int_index()
andint_to_grid_index()
method to convert to and from grid indices in these archives.
add()
formerly operated on single solutions. Now, it inserts solutions into the archive in batch. There is also anadd_single()
which inserts solutions one at a time. The source code foradd_single()
is more amenable to modifications than that of the batchedadd()
method.get_random_elite()
, which sampled one elite from the archive, has been replaced with a batchedsample_elites()
method which samples multiple elites at once.The
elite_with_behavior()
method which retrieved one elite with given measures has been replaced withretrieve()
, which retrieves a batch of such elites.
Some of these methods also include “single” versions which operate on single solutions, e.g., index_of_single()
returns the integer index of a single measures array.
EliteBatch¶
We have added an EliteBatch
class to represent batches of elites.
ArchiveDataFrame Column Renaming¶
To reflect the terminology changes and the switch to integer indices in archives, columns in ArchiveDataFrame
(returned by as_pandas()
) are as follows:
index | measure_0 | … | objective | solution_0 | … | metadata |
---|
Before, they were:
index_0 | … | behavior_0 | … | objective | solution_0 | … | metadata |
---|
We have also renamed the ArchiveDataFrame
methods as follows:
Old Name | New Name |
---|---|
| |
| |
| |
| |
|
Miscellaneous¶
Finally, here are several miscellaneous improvements we have made to pyribs.
Removal of initialize() Method for Archives¶
Previously, archives required calling initialize(solution_dim)
after being constructed. This method was typically called by the Optimizer/Scheduler. Now, archives are directly constructed with the solution_dim
argument for simplicity.
# v0.4.0 (OLD)
archive = GridArchive(...)
archive.initialize(solution_dim) # Would be called by Optimizer / Scheduler.
# v0.5.0 (NEW)
archive = GridArchive(solution_dim, ...)
More Flexible Visualization Tools¶
In all heatmap visualization tools, we have made the colorbar more flexible by adding a cbar
option to control which axes the colorbar appears on and a cbar_kwargs
option to pass arguments directly to Matplotlib’s colorbar()
.
from ribs.visualize import grid_archive_heatmap # cvt_archive_heatmap and sliding_boundaries_archive_heatmap also work
archive = ...
grid_archive_heatmap(archive, cbar="auto") # Display the colorbar as part of the current axes (default).
grid_archive_heatmap(archive, cbar=None) # Don't display the colorbar at all.
grid_archive_heatmap(archive, cbar=cbar_ax) # Display colorbar on a custom Axes.
grid_archive_heatmap(archive, ..., cbar_kwargs={...}) # Pass arguments to the colorbar.
In addition:
We have added an
aspect
argument which can set the aspect ratio of the heatmap, i.e., the ratioheight / width
.We now support heatmaps for 1D grid archives.
Continuous Quality Diversity (CQD) Score¶
We support computing the Continuous Quality Diversity (CQD) Score in all archives with the cqd_score()
method.
ArchiveStats¶
The ArchiveStats
object now includes the normalized QD score (i.e., the QD score divided by the number of cells in the archive). Furthermore, ArchiveStats
is now a dataclass rather than a namedtuple.
archive.stats.norm_qd_score # Normalized QD score.
Deprecation of Positional Arguments¶
Following scikit-learn, almost all constructor arguments must now be passed in as keyword arguments. Given the many parameters that these objects have, this makes it easier to see what each parameter means.
To illustrate, the signature for EvolutionStrategyEmitter
is:
EvolutionStrategyEmitter(archive, *, x0, sigma0, ranker='2imp', es='cma_es', es_kwargs=None, selection_rule='filter', restart_rule='no_improvement', bounds=None, batch_size=None, seed=None)
All parameters after the *
are keyword-only. The following will result in an error:
EvolutionStrategyEmitter(archive, np.zeros(10), 0.1)
While the following will be accepted:
EvolutionStrategyEmitter(archive, x0=np.zeros(10), sigma=0.1)
Input Validation¶
Many of our methods, e.g., the archives’ add()
method and schedulers’ ask()
and tell()
methods, now have input validation to help catch common argument errors. For example, we check that arguments are the correct shape, and we check that they do not have NaN
or inf
values.
Deprecation of ribs.factory¶
We have removed ribs.factory
as it is out of scope for the current library.