GithubHelp home page GithubHelp logo

nnaisense / evotorch Goto Github PK

View Code? Open in Web Editor NEW
973.0 16.0 58.0 43.7 MB

Advanced evolutionary computation library built directly on top of PyTorch, created at NNAISENSE.

Home Page: https://evotorch.ai

License: Apache License 2.0

Python 100.00%
artificial-intelligence evolutionary-computation neural-networks optimization-algorithms distributed gpu python pytorch optimization reinforcement-learning

evotorch's Introduction


Welcome to the EvoTorch project! EvoTorch is an open source evolutionary computation library developed at NNAISENSE, built on top of PyTorch. See the documentation for in-depth guidance about using EvoTorch, and join us on Slack for discussions.

Get started by installing EvoTorch:

pip install evotorch

With EvoTorch, one can solve various optimization problems, regardless of whether they are differentiable (i.e. allow gradient descent). Among the problem types that are solvable with EvoTorch are:

  • Black-box optimization problems (continuous or discrete)
  • Reinforcement learning tasks
  • Supervised learning tasks

Various evolutionary computation algorithms are available in EvoTorch:

  • Distribution-based search algorithms:
    • PGPE: Policy Gradients with Parameter-based Exploration.
    • XNES: Exponential Natural Evolution Strategies.
    • CMA-ES: Covariance Matrix Adaptation Evolution Strategies.
    • SNES: Separable Natural Evolution Strategies.
    • CEM: Cross Entropy Method.
  • Population-based search algorithms:
    • GeneticAlgorithm: A genetic algorithm implementation. Also supports multiple objectives, in which case it behaves like NSGA-II.
    • CoSyNE: Cooperative Synapse Neuroevolution.
    • MAPElites: Multi-dimensional Archive of Phenotypic Elites

Since all of these algorithms are implemented in PyTorch, they benefit from use of vectorization and parallelization on GPUs, drastically speeding up optimization when GPUs are available. Using Ray, EvoTorch scales these algorithms even further by splitting the workload across:

  • multiple CPUs
  • multiple GPUs
  • multiple computers in a Ray cluster

Examples

Below are some code examples that demonstrate the API of EvoTorch.

A black-box optimization example

Any objective function defined to work with PyTorch can be used directly with EvoTorch. A non-vectorized objective function simply receives a solution as a 1-dimensional torch tensor, and returns a fitness as a scalar. A vectorized objective function receives a batch of solutions as a 2-dimensional torch tensor, and returns a 1-dimensional tensor of fitnesses. The following example demonstrates how to define and solve the classical Rastrigin problem.

from evotorch import Problem
from evotorch.algorithms import SNES
from evotorch.logging import StdOutLogger, PandasLogger
import math
import matplotlib.pyplot as plt
import torch


# Declare the objective function
def rastrigin(x: torch.Tensor) -> torch.Tensor:
    A = 10
    (_, n) = x.shape
    return A * n + torch.sum((x**2) - A * torch.cos(2 * math.pi * x), 1)


# Declare the problem
problem = Problem(
    "min",
    rastrigin,
    initial_bounds=(-5.12, 5.12),
    solution_length=100,
    vectorized=True,
    # device="cuda:0"  # enable this line if you wish to use GPU
)

# Initialize the SNES algorithm to solve the problem
searcher = SNES(problem, popsize=1000, stdev_init=10.0)

# Initialize a standard output logger, and a pandas logger
_ = StdOutLogger(searcher, interval=10)
pandas_logger = PandasLogger(searcher)

# Run SNES for the specified amount of generations
searcher.run(2000)

# Get the progress of the evolution into a DataFrame with the
# help of the PandasLogger, and then plot the progress.
pandas_frame = pandas_logger.to_dataframe()
pandas_frame["best_eval"].plot()
plt.show()

A reinforcement learning example

The following example demonstrates how to solve reinforcement learning tasks that are available through the gym library.

from evotorch.algorithms import PGPE
from evotorch.logging import StdOutLogger, PicklingLogger
from evotorch.neuroevolution import GymNE

# Declare the problem to solve
problem = GymNE(
    env="Humanoid-v4",  # Solve the Humanoid-v4 task
    network="Linear(obs_length, act_length)",  # Linear policy
    observation_normalization=True,  # Normalize the policy inputs
    decrease_rewards_by=5.0,  # Decrease each reward by 5.0
    num_actors="max",  # Use all available CPUs
    # num_actors=4,    # Explicit setting. Use 4 actors.
)

# Instantiate a PGPE algorithm to solve the problem
searcher = PGPE(
    problem,
    # Base population size
    popsize=200,
    # For each generation, sample more solutions until the
    # number of simulator interactions reaches this threshold
    num_interactions=int(200 * 1000 * 0.75),
    # Stop re-sampling solutions if the current population size
    # reaches or exceeds this number.
    popsize_max=3200,
    # Learning rates
    center_learning_rate=0.0075,
    stdev_learning_rate=0.1,
    # Radius of the initial search distribution
    radius_init=0.27,
    # Use the ClipUp optimizer with the specified maximum speed
    optimizer="clipup",
    optimizer_config={"max_speed": 0.15},
)

# Instantiate a standard output logger
_ = StdOutLogger(searcher)

# Optional: Instantiate a logger to pickle and save the results periodically.
# In this example, among the saved results will be the center of the search
# distribution, since we are using PGPE which is distribution-based.
_ = PicklingLogger(searcher, interval=10)

# Run the algorithm for the specified amount of generations
searcher.run(500)

# Get the center point of the search distribution,
# obtain a policy out of that point, and visualize the
# agent using that policy.
center_solution = searcher.status["center"]
trained_policy = problem.make_net(center_solution)
problem.visualize(trained_policy)

More examples can be found here.

How to cite

If you use EvoTorch in your research, please consider citing our paper.

@article{evotorch2023arxiv,
  title={{EvoTorch}: Scalable Evolutionary Computation in {Python}},
  author={Toklu, Nihat Engin and Atkinson, Timothy and Micka, Vojt\v{e}ch and Liskowski, Pawe\l{} and Srivastava, Rupesh Kumar},
  journal={arXiv preprint},
  year={2023},
  note={https://arxiv.org/abs/2302.12600}
}

How to Contribute

Please see our contribution guidelines.

Authors

evotorch's People

Contributors

engintoklu avatar flukeskywalker avatar galatolofederico avatar higgcz avatar naturalgradient avatar pre-commit-ci[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

evotorch's Issues

Simple example scripts

Simpler example scripts that demonstrate basic usage without extra dependencies (such as Sacred) will help new users get started.

neuroevolution - activation functions, prefab substructures, how much of PyTorch api is available ?

Hi,
I did a lot of neuroevolution and evolutionary computing work long ago but I have not attempted it in the PyTorch world. Is there somewhere in the documentation or the code where I can focus on what the possible ingredients of evolution will be? In NEAT there was a limited set of operators or structural components which could comprise a solution.

Also is it possible to add evolved or hand-coded structures to the set of structures which can be incorporated into the evolutionary process?

Also where can I find out more about the weights or other evolved parameters? Are all these lost after evolution and the individual has to be retrained? It might be good to be able to fine tune an evolved individual but since these are prototypes I understand that might not be the intention.

Also is there a grammar for the string representation of a network? I am interested in compressing individuals to speed the search and it seems that a string or symbolic representation might work, and also I would like to try to incorporate guided evolution every few generations using a fine-tuned LLM and the string representation might provide a shortcut for this.

The order of sample and update

I have observed that in the current evotorch, it seems that it is only possible to sample first and then update, which may be inconvenient for certain use cases.
For example, I am applying the CMA algorithm to a black-box optimization problem. In this problem, obtaining the fitness of a batch of solutions may take some time, so I would like the interface to be able to complete one step in the order of "obtain fitness -> update parameters -> resample". However, the current _step function does not support such idea. I wonder if there could be any improvements in this regard?

GNN-based Meta-Learning for Sparse Portfolio Optimization

Hello,

Let me start by saying that I am a fan of your work here. I have recently open-sourced by GNN-based meta-learning method for optimization. I have applied it to the sparse index-tracking problem from real-world (after an initial benchmarking on Schwefel function), and it seems to outperform Fast CMA-ES significantly both in terms of producing robust solutions on the blind test set and also in terms of time (total duration and iterations) and space complexity. I include the link to my repository here, in case you would consider adding the method or the benchmarking problem to your repository. Note: GNN, which learns how to generate populations of solutions at each iteration, is trained using gradients of the loss function, as opposed to black-box algorithms here.

x

Sincerely, K

Notifying the user about the Problem configuration

It would be helpful if the Problem object, upon instantiation, notified the user regarding its effective configuration. The notification text could contain:

  • number of actors
  • device (which device is being used for the population)
  • dtype
  • eval_dtype (dtype that is being used for the fitnesses)
  • etc.

Question about ES-HyperNEAT integration

Hi! Neat project, thanks for making it available. I've been experimenting with ES-HyperNEAT using Gym wrappers. I am curious if an ES-HyperNEAT custom Gym implementation with SteadyStateGA would be feasible and parallelize'able to GPU?

Documentation of NeptuneLogger

Currently, if the user has neptune-client installed, they will be able to use the evotorch.logging.NeptuneLogger logger class to remotely log to Neptune.

This feature is currently undocumented. Corresponding documentation should therefore be added to User Guide/Logging.

SupervisedNE get_minibatch stack overflow

Hello, I'm trying out evotorch to eventually do some black box optimization on the YOLOv8 model. However, I've run into the following error when trying to run SNES on a SupervisedNE problem on the COCO dataset.

Here is the console output:

(praeception-py3.8) jesse@caliban:~/git/praeception$ python scripts/try_evotorch_on_yolo.py 

                   from  n    params  module                                       arguments                     
  0                  -1  1       464  ultralytics.nn.modules.Conv                  [3, 16, 3, 2]                 
  1                  -1  1      4672  ultralytics.nn.modules.Conv                  [16, 32, 3, 2]                
  2                  -1  1      7360  ultralytics.nn.modules.C2f                   [32, 32, 1, True]             
  3                  -1  1     18560  ultralytics.nn.modules.Conv                  [32, 64, 3, 2]                
  4                  -1  2     49664  ultralytics.nn.modules.C2f                   [64, 64, 2, True]             
  5                  -1  1     73984  ultralytics.nn.modules.Conv                  [64, 128, 3, 2]               
  6                  -1  2    197632  ultralytics.nn.modules.C2f                   [128, 128, 2, True]           
  7                  -1  1    295424  ultralytics.nn.modules.Conv                  [128, 256, 3, 2]              
  8                  -1  1    460288  ultralytics.nn.modules.C2f                   [256, 256, 1, True]           
  9                  -1  1    164608  ultralytics.nn.modules.SPPF                  [256, 256, 5]                 
 10                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          
 11             [-1, 6]  1         0  ultralytics.nn.modules.Concat                [1]                           
 12                  -1  1    148224  ultralytics.nn.modules.C2f                   [384, 128, 1]                 
 13                  -1  1         0  torch.nn.modules.upsampling.Upsample         [None, 2, 'nearest']          
 14             [-1, 4]  1         0  ultralytics.nn.modules.Concat                [1]                           
 15                  -1  1     37248  ultralytics.nn.modules.C2f                   [192, 64, 1]                  
 16                  -1  1     36992  ultralytics.nn.modules.Conv                  [64, 64, 3, 2]                
 17            [-1, 12]  1         0  ultralytics.nn.modules.Concat                [1]                           
 18                  -1  1    123648  ultralytics.nn.modules.C2f                   [192, 128, 1]                 
 19                  -1  1    147712  ultralytics.nn.modules.Conv                  [128, 128, 3, 2]              
 20             [-1, 9]  1         0  ultralytics.nn.modules.Concat                [1]                           
 21                  -1  1    493056  ultralytics.nn.modules.C2f                   [384, 256, 1]                 
 22        [15, 18, 21]  1    897664  ultralytics.nn.modules.Detect                [80, [64, 128, 256]]          
YOLOv8n summary: 225 layers, 3157200 parameters, 3157184 gradients, 8.9 GFLOPs

loading annotations into memory...
Done (t=9.30s)
creating index...
index created!
[2023-03-11 18:42:04] INFO     <499881> evotorch.core: Instance of `SupervisedNE` (id:140117468367792) -- The `dtype` for the problem's decision variables is set as torch.float32
[2023-03-11 18:42:04] INFO     <499881> evotorch.core: Instance of `SupervisedNE` (id:140117468367792) -- `eval_dtype` (the dtype of the fitnesses and evaluation data) is set as torch.float32
[2023-03-11 18:42:04] INFO     <499881> evotorch.core: Instance of `SupervisedNE` (id:140117468367792) -- The `device` of the problem is set as cuda:0
[2023-03-11 18:42:05] INFO     <499881> evotorch.core: Instance of `SupervisedNE` (id:140117468367792) -- The number of actors that will be allocated for parallelized evaluation is 0
Fatal Python error: Cannot recover from stack overflow.
Python runtime state: initialized

Current thread 0x00007f7039a8d740 (most recent call first):
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/PIL/ImageFile.py", line 571 in _safe_read
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/PIL/JpegImagePlugin.py", line 67 in APP
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/PIL/JpegImagePlugin.py", line 386 in _open
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/PIL/ImageFile.py", line 117 in __init__
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/PIL/JpegImagePlugin.py", line 822 in jpeg_factory
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/PIL/Image.py", line 3254 in _open_core
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/PIL/Image.py", line 3268 in open
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/torchvision/datasets/coco.py", line 41 in _load_image
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/torchvision/datasets/coco.py", line 48 in __getitem__
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/torch/utils/data/_utils/fetch.py", line 58 in <listcomp>
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/torch/utils/data/_utils/fetch.py", line 58 in fetch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/torch/utils/data/dataloader.py", line 671 in _next_data
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/torch/utils/data/dataloader.py", line 628 in __next__
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 318 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  File "/home/jesse/.cache/pypoetry/virtualenvs/praeception--NwHCx9X-py3.8/lib/python3.8/site-packages/evotorch/neuroevolution/supervisedne.py", line 326 in get_minibatch
  ...
Aborted (core dumped)

And here is the code I'm using:

import click
import torch
from evotorch.algorithms import SNES
from evotorch.logging import StdOutLogger
from evotorch.neuroevolution import SupervisedNE
from torchvision.datasets import CocoDetection
from ultralytics import YOLO


@click.command()
@click.option("--model", default="yolov8n.yaml", help="Model config file or model path")
@click.option("--device", default="cuda:0", help="Device to use")
def main(model, device):

    yolo_model = YOLO(model=model)

    coco_path = "/data/school/coco/train2017"
    ann_path = "/data/school/coco/annotations/instances_train2017.json"

    dataset = CocoDetection(coco_path, ann_path)

    problem = SupervisedNE(
        dataset=dataset,
        network=yolo_model.model,
        minibatch_size=16,
        loss_func=torch.nn.MSELoss(),
        device=device,
        num_actors=4,
        num_gpus_per_actor=1.0 / 4.0,
    )
    searcher = SNES(problem, popsize=3, radius_init=2.25)
    _ = StdOutLogger(searcher)
    searcher.run(1)


if __name__ == "__main__":
    main()

Looking at the source code for get_minibatch in SupervisedNE it appears that if the batch returns None or there is an exception then get_minibatch is called again. This would appear to lead to an infinite regress until overflow and no underlying error is thrown to let me know what the problem is. I tried it on a few other datasets as well and got the same result.

Thank you!

Adding a "Citing evotorch" section

Hi guys 👋

How should your work should be cited in scientific publication?
Maybe you could add it in the bottom of your README?

I guess it will look approx. like that:

@software{evotorch2022github,
  author = {...},
  title = {...},
  url = {https://github.com/nnaisense/evotorch},
  year = {2022},
}

Thanks and well done for your library!

Add notes on reproducibility to documentation

This is related to scientific comparisons but also checkpointing/resuming a search, as pointed out by user DTrescher on Slack.

Even if full reproducibility is not possible, we can clarify to what extent it is.

Unable to solve for integer decision variables

I have a problem which requires an integer solution, when running my searcher I get the error RuntimeError: "normal_kernel_cpu" not implemented for 'Int'

Here is an example, if dtype=torch.float it works fine, and torch.prod(torch.tensor([2,3], dtype=torch.int)) works as expected.

import torch
from evotorch import Problem
from evotorch.algorithms import SNES
from evotorch.logging import StdOutLogger

def prod(x: torch.Tensor) -> torch.Tensor:
  return torch.prod(x,dim=-1)

problem = Problem(
"min",
prod,
initial_bounds=(-10, 10),
solution_length=100,
vectorized=True,
dtype=torch.int,
)

searcher = SNES(problem, popsize=1000, stdev_init=10)
_ = StdOutLogger(searcher, interval=50)

searcher.run(num_generations=100)

I've got the same error on Red Hat Linux and my M1 Mac, with python 3.9 and 3.10 and evotorch 0.2.0.

Missing documentation regarding non-numeric solutions

EvoTorch has the capability to work with non-numeric solution structures such as variable-length lists, dictionaries, etc. (with dtype=object).

We are currently missing documentation pages (in User Guide and/or in Advanced Usage) and examples (probably in the form of Jupyter notebooks) explaining the details of this feature.

Further batching

Hi, im new to this library so it might be hidden very will in the docs.
But never the less, I am training on a custom gym environment but for the same of recreation lets just take the MPC example given in the docs:
https://docs.evotorch.ai/v0.4.1/examples/notebooks/reacher_mpc/

Gym allow us to run multiple environments at the same time while everything is being batched.
This adds the extra dimension of world_dim into observations and actions.
however I cannot find a way for evotorch to allow an extra batch dimension and stuck with the (popsize, solution_size) and (popsize, 1) for evaluation size. Is there a way to expand these to (popsize, world_dim, solution_size) and (popsize, world_dim, 1)?

Stopping and resuming SearchAlgorithm

How do I stop and resume a search for a problem that takes a long time to solve?
Should I pickle the search algorithm itself?
PicklingLogger does not pickle the search algorithm so it can't be used.

I do see a 'reset_first_step_datetime' parameter associated with the 'run' method of a search algorithm but I am unable to understand its supposed use case.

[Feature request] Make the is_terminated property manipulable

Hi there,

first off, I'm new to evotorch and must say that I enjoy it a lot so far. The (basic) things I tried work out of the box, the hooks are awesome, and the tutorial makes the entrance hurdle really low,

That being said, I just discovered the is_terminated property of SeachAlgorithm which seems to be False in any case. How about turning this property into a read-only for an internal self._is_terminated that the user could manipulate?
My goal is to sneak in a custom stopping criterion via the searchers before_eval_hook. Actually, my stopping criterion is a stateful instance of a custom class. Do you think it would be the right way to sneak this object into the searcher instance via a hook?
Moreover, I think that a beginning_of_run_hook (similar to the existing end_of_run_hook) would be a nice addition.

Best wishes,
Fabio

TypeError: field() got an unexpected keyword argument 'alias'

Running the Quickstart example from the evotorch website, I get the following error:

Traceback (most recent call last):
  File "/Users/jaime/Documents/PhD/golf-env/notebooks/et.py", line 1, in <module>
    from evotorch import Problem
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/evotorch/__init__.py", line 31, in <module>
    from . import core
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/evotorch/core.py", line 33, in <module>
    import ray
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/ray/__init__.py", line 123, in <module>
    from ray._private.worker import (  # noqa: E402,F401
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/ray/_private/worker.py", line 56, in <module>
    import ray.actor
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/ray/actor.py", line 38, in <module>
    from ray.util.tracing.tracing_helper import (
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/ray/util/tracing/tracing_helper.py", line 29, in <module>
    from ray.runtime_context import get_runtime_context
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/ray/runtime_context.py", line 9, in <module>
    from ray.runtime_env import RuntimeEnv
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/ray/runtime_env/__init__.py", line 1, in <module>
    from ray.runtime_env.runtime_env import RuntimeEnv, RuntimeEnvConfig  # noqa: E402,F401
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/ray/runtime_env/runtime_env.py", line 12, in <module>
    from ray._private.runtime_env.plugin_schema_manager import RuntimeEnvPluginSchemaManager
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/ray/_private/runtime_env/plugin_schema_manager.py", line 2, in <module>
    import jsonschema
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/jsonschema/__init__.py", line 13, in <module>
    from jsonschema._format import FormatChecker
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/jsonschema/_format.py", line 11, in <module>
    from jsonschema.exceptions import FormatError
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/jsonschema/exceptions.py", line 15, in <module>
    from referencing.exceptions import Unresolvable as _Unresolvable
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/referencing/__init__.py", line 4, in <module>
    from referencing._core import Anchor, Registry, Resource, Specification
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/referencing/_core.py", line 29, in <module>
    class Specification(Generic[D]):
  File "/Users/jaime/opt/anaconda3/envs/jrs0001/lib/python3.8/site-packages/referencing/_core.py", line 55, in Specification
    ] = field(alias="anchors_in")
TypeError: field() got an unexpected keyword argument 'alias'

with:

  • python 3.8.16
  • evotorch==0.4.1

having tried (requirements already satisfied):

pip install --upgrade referencing jsonschema

Able to suppress INFO logs

Hi, it seems everytime a user instantiates a SupervisedNE problem, INFO logs appear in jupyter cell and can't seem to disable it with typical methods like logging.basicConfig or .setLevel(logging.WARNING).

`Problem` and algorithms ignore the `torch.set_default_dtype`

I just ran into a problem when trying to run problems with double precision. I thought that defining torch.set_default_dtype(torch.float64) would be enough for evotorch to define all the tensors internally to be of double precision, but this is not the case.

Consider the following simple example of running CMA-ES for a single step:

import torch
import numpy as np

from evotorch import Problem
from evotorch.algorithms import CMAES

torch.set_default_dtype(torch.float64)

# A simple objective function
def objective_function(xy: torch.Tensor) -> torch.Tensor:
    x = xy[..., 0]
    y = xy[..., 1]
    return x + y


# Defining the problem
problem = Problem(
    "max",
    objective_function,
    bounds=[0.0, 1.0],
    solution_length=2,
    vectorized=True,
)

# Defining the searcher
cmaes = CMAES(
    problem,
    popsize=100,
    stdev_init=1.0,
    center_learning_rate=0.1,
    cov_learning_rate=0.1,
)

# Taking a single step
cmaes.step()

# Accessing the current best's dtype
# (thought it was float64, but **it's only float32**)
print(cmaes.get_status_value("pop_best").values.dtype)

If we want it to be float64, we have to specify it in the definition of problem. Indeed, running this with

problem = Problem(
    "max",
    objective_function,
    bounds=[0.0, 1.0],
    solution_length=2,
    vectorized=True,
    dtype=torch.float64,
)

gets us a best candidate with double precision. Why do we have to specify the type twice? Wouldn't we want Problem to inherit the default float dtype?

`num_actors` Fails

I'm testing examples locallly, but unable to exploit available GPUs.
When setting num_actors to any integer graeter than 1, it'll cause an error:

RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cpu and cuda:0! (when checking argument for argument mat2 in method wrapper_mm)

Bug when accessing SolutionBatch with after_eval hook

Hi. With Jupyter notebook, the following script:

import torch
from evotorch.neuroevolution import NEProblem
from evotorch.algorithms import CMAES
from evotorch.logging import PandasLogger
from evotorch.neuroevolution.net import misc
from functools import partial
from sklearn.datasets import make_regression


X, y = make_regression(n_features=10)
X, y = (X - X.mean()) / X.std(), (y - y.mean()) / y.std()
X, y = torch.tensor(X, dtype=torch.float32), torch.tensor(y, dtype=torch.float32)

pop = 100


class NET(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.lin1 = torch.nn.Linear(10, 32)
        self.act = torch.nn.SELU()
        self.lin2 = torch.nn.Linear(32, 1)

    def forward(self, x):
        return self.lin2(self.act(self.lin1(x)))

    
def eval_net(net, X, y):
    y_ = net(X)
    loss = (y.reshape(-1,1) - y_.reshape(-1,1))**2 / len(y)
    return loss.mean()
eval_net = partial(eval_net, X=X, y=y)


prob = NEProblem(objective_sense="min",
                network=NET,
                #network_args={"hidden_dim": 17},
                network_eval_func=eval_net)
prob.after_eval_hook.append(lambda x: print(x.access_values().mean(), end=" "))
searcher = CMAES(prob, popsize=pop, stdev_init=2, separable=True)   # best
pandas_logger = PandasLogger(searcher)
searcher.run(5)
progress = pandas_logger.to_dataframe()
progress

gives NaNs and Nones in pandas output:

  | stepsize | pop_best_eval | mean_eval | median_eval | best_eval | worst_eval
-- | -- | -- | -- | -- | -- | --

ReadOnlyTensor(1.9160) | None | NaN | NaN | 9.0076 | 92.7398
ReadOnlyTensor(1.8508) | None | NaN | NaN | 8.2423 | 102.1744
ReadOnlyTensor(1.8003) | None | NaN | NaN | 8.2375 | 102.1744
ReadOnlyTensor(1.7599) | None | NaN | NaN | 6.0024 | 102.1744
ReadOnlyTensor(1.7278) | None | NaN | NaN | 6.0024 | 102.1744

By simply changing the hook to before like prob.before_eval_hook.append(lambda x: print(x.access_values().mean(), end=' ')) gives expected pandas output:

stepsize | pop_best_eval | mean_eval | median_eval | best_eval | worst_eval
-- | -- | -- | -- | -- | --

ReadOnlyTensor(1.9157) | 6.5819 | 33.0637 | 31.3136 | 6.5819 | 106.6191
ReadOnlyTensor(1.8512) | 6.6168 | 27.2860 | 24.6014 | 6.5819 | 106.6191
ReadOnlyTensor(1.7997) | 6.7817 | 24.7794 | 21.2962 | 6.5819 | 106.6191
ReadOnlyTensor(1.7566) | 5.9974 | 21.6505 | 19.8498 | 5.9974 | 106.6191
ReadOnlyTensor(1.7214) | 5.8343 | 21.8427 | 19.2835 | 5.8343 | 106.6191

Action Clipping Wrapper

Hi! For GymNE problems, I see the Action Clipping wrapper is added automatically to the policy when calling the to_policy() method. However, I don't think this method is called during the training, is this intended? Shouldn't actions be rescaled and clipped during training (as also done here).

Thank you!

Multi-Agent Environments for Crowd/Predator-Prey Simulations and Melee/Ranged Combat

Hello again,

I hope that you're doing well.

I am creating some multi-agent RL environments, as mentioned in the title, and got interesting results for the crowd and predator-prey simulations where in the latter, there is a game-theoretic relationship in-between.

Here is the outcome of predator-prey: https://www.linkedin.com/feed/update/urn:li:activity:7023631787763355648/
The source codes for those various simulations are available here: https://github.com/kayuksel/multi-rl-crowd-sim

I am also working on more interesting self-play army simulations with the same logic. I am writing to invite you to collaborate as I am working alone on this hobby project of mine, and maybe integrating them to evotorch.

(I am also planning to finish a competitive multi-agent closed-market auction environment later.)

Sincerely,
Kamer

Migrating from pgpelib to evotorch

Hi! I am a "mindless" user of pgpelib (using it without really understanding what is down the hood). I saw the release of evotorch and I am wondering if it is worth swapping in all cases. And I would like to also understand how could I adapt an existing pgpelib code to evotorch if that even makes sense

Currently the code I have does something like:

pgpe = PGPE(
    solution_length= SOLUTION_LENGTH,   # A solution vector has the length of 5
    popsize= NUM_SOLUTIONS,          # Our population size

    optimizer='clipup',          # Uncomment these lines if you
    optimizer_config = dict(     # would like to use the ClipUp
       max_speed=0.15,           # optimizer.
       momentum=0.9
    ),
)

And then to run I do it like this

for generation in range(1000):
    # create new solutions
    solutions = pgpe.ask()

    # evaluate fitnesses
    fitnesses = [evaluate_solution(genes) for genes in solutions]
   
    # update the population  
    pgpe.tell(fitnesses)

    # Saving the best in the generation
    fitness, canvas = evaluate_solution(pgpe.center, returns_image=True)
    canvas = draw_fitness(canvas, generation, fitness)

    # Store the best 
    if fitness > best_fitness:
      best_fitness = fitness
      best_generation = generation
      best_solution = pgpe.center
fitness, canvas = evaluate_solution(best_solution, returns_image=True)
canvas = draw_fitness(canvas, generation, fitness)

It wasn't super clear how best to adapt it to evotorch or even if it would be beneficial to do so. Thank you!

CMAES._get_sigma assumes sigma to be a singleton

I suspect this to be a bug, however, did not spend much time with your CMAES implementation.

This line tries to cast self.sigma to a building float.
I think that for multidim problems this could be a vector (torch.Tensor). At least during initialization, it is a tensor.

If I am correct, the float(...) could be turned into a self.sigma.to(device="cpu", dtype=torch.float)

Thanks for looking at this,
Fabio

Custom RL Environment Issue with GymNE

When making a problem like this:

problem = GymNE(
    env = env,
    network="Linear(obs_length, act_length)",
    observation_normalization=True,
    num_episodes=20, # each solution evaluated on 20 episodes
    num_actors="max",
)

where env is a gym environment made with gym.make("CartPole-v1"), I get the following error.
Screen Shot 2022-12-16 at 2 20 12 PM

I modified the GymNE file as shown below, and it fixed the problem. There might be a better way to do it, but this works.

Screen Shot 2022-12-16 at 2 20 56 PM

Improve MAPElites performance using torch_scatter

Would you be interested in contributions to re-work MAPElites to use torch_scatter rather than the vmaped extended_population x feature_grid operation?

The general gist is:

  • Quantize features and round them to longs
  • Get the indexes for each elite for each volume using scatter_max (which returns argmaxes)
  • Map the evals and values from the extended population to the population using the indexes

problem._get_best_and_worst

Is there something wrong with the implementation?
It seems that when len(senses)==1 and self._best is None, only one of _best and _worst will be set, while the other will remain None. This could cause an error because both _best and _worst will be accessed when the function returns.

    @torch.no_grad()
    def _get_best_and_worst(self, batch: "SolutionBatch") -> Optional[dict]:
        if self._store_solution_stats is None:
            self._store_solution_stats = str(batch.device) == "cpu"

        if not self._store_solution_stats:
            return {}

        senses = self.senses
        nobjs = len(senses)

        if self._best is None:
            self._best_evals = self.make_empty(nobjs, device=batch.device, use_eval_dtype=True)
            self._worst_evals = self.make_empty(nobjs, device=batch.device, use_eval_dtype=True)
            for i_obj in range(nobjs):
                if senses[i_obj] == "min":
                    self._best_evals[i_obj] = float("inf")
                    self._worst_evals[i_obj] = float("-inf")
                elif senses[i_obj] == "max":
                    self._best_evals[i_obj] = float("-inf")
                    self._worst_evals[i_obj] = float("inf")
                else:
                    raise ValueError(f"Invalid sense: {senses[i_obj]}")
            self._best = [None] * nobjs
            self._worst = [None] * nobjs

        def first_is_better(a, b, i_obj):
            if senses[i_obj] == "min":
                return a < b
            elif senses[i_obj] == "max":
                return a > b
            else:
                raise ValueError(f"Invalid sense: {senses[i_obj]}")

        def first_is_worse(a, b, i_obj):
            if senses[i_obj] == "min":
                return a > b
            elif senses[i_obj] == "max":
                return a < b
            else:
                raise ValueError(f"Invalid sense: {senses[i_obj]}")

        best_sln_indices = [batch.argbest(i) for i in range(nobjs)]
        worst_sln_indices = [batch.argworst(i) for i in range(nobjs)]

        for i_obj in range(nobjs):
            print(i_obj)
            best_sln_index = best_sln_indices[i_obj]
            worst_sln_index = worst_sln_indices[i_obj]
            scores = batch.access_evals(i_obj)
            best_score = scores[best_sln_index]
            worst_score = scores[worst_sln_index]
            if first_is_better(best_score, self._best_evals[i_obj], i_obj):
                self._best_evals[i_obj] = best_score
                self._best[i_obj] = batch[best_sln_index].clone()
            if first_is_worse(worst_score, self._worst_evals[i_obj], i_obj):
                self._worst_evals[i_obj] = worst_score
                self._worst[i_obj] = batch[worst_sln_index].clone()
        
        if len(senses) == 1:
            return dict(
                best=self._best[0],
                worst=self._worst[0],
                best_eval=float(self._best[0].evals[0]),
                worst_eval=float(self._worst[0].evals[0]),
            )
        else:
            return {"best": self._best, "worst": self._worst}

Serialization error when fixing seed.

Hello,

Is there a way to fix seed when num_actor is greater than 1 ?

The following code seems to give an error because torch._C.Generator cannot be serialized.

from evotorch import Problem
from evotorch.algorithms import SNES
from evotorch.logging import StdOutLogger
import torch

def sphere(x: torch.Tensor) -> torch.Tensor:
    return torch.sum(x.pow(2.0))

p = Problem(
    "min", sphere, solution_length=10, initial_bounds=(-1, 1),
    num_actors=4, seed=42
)
searcher = SNES(p, stdev_init=5)
logger = StdOutLogger(searcher)
searcher.step()

Error messages:

TypeError                                 Traceback (most recent call last)
File python/ray/_raylet.pyx:441, in ray._raylet.prepare_args_internal()

File ~/python/evotorch/lib/python3.9/site-packages/ray/_private/serialization.py:450, in SerializationContext.serialize(self, value)
    449 else:
--> 450     return self._serialize_to_msgpack(value)

File ~/python/evotorch/lib/python3.9/site-packages/ray/_private/serialization.py:428, in SerializationContext._serialize_to_msgpack(self, value)
    427     metadata = ray_constants.OBJECT_METADATA_TYPE_PYTHON
--> 428     pickle5_serialized_object = self._serialize_to_pickle5(
    429         metadata, python_objects
    430     )
    431 else:

File ~/python/evotorch/lib/python3.9/site-packages/ray/_private/serialization.py:390, in SerializationContext._serialize_to_pickle5(self, metadata, value)
    389     self.get_and_clear_contained_object_refs()
--> 390     raise e
    391 finally:

File ~/python/evotorch/lib/python3.9/site-packages/ray/_private/serialization.py:385, in SerializationContext._serialize_to_pickle5(self, metadata, value)
    384     self.set_in_band_serialization()
--> 385     inband = pickle.dumps(
    386         value, protocol=5, buffer_callback=writer.buffer_callback
    387     )
    388 except Exception as e:

File ~/python/evotorch/lib/python3.9/site-packages/ray/cloudpickle/cloudpickle_fast.py:73, in dumps(obj, protocol, buffer_callback)
     70 cp = CloudPickler(
     71     file, protocol=protocol, buffer_callback=buffer_callback
     72 )
---> 73 cp.dump(obj)
     74 return file.getvalue()

File ~/python/evotorch/lib/python3.9/site-packages/ray/cloudpickle/cloudpickle_fast.py:627, in CloudPickler.dump(self, obj)
    626 try:
--> 627     return Pickler.dump(self, obj)
    628 except RuntimeError as e:

File ~/python/evotorch/lib/python3.9/site-packages/evotorch/tools/cloning.py:285, in Serializable.__getstate__(self)
    284 memo = {id(self): self}
--> 285 return self._get_cloned_state(memo=memo)

File ~/python/evotorch/lib/python3.9/site-packages/evotorch/core.py:2565, in Problem._get_cloned_state(self, memo)
   2564             with _no_grad_if_basic_dtype(self.dtype):
-> 2565                 result[k] = deep_clone(
   2566                     v,
   2567                     otherwise_deepcopy=True,
   2568                     memo=memo,
   2569                 )
   2570 return result

File ~/python/evotorch/lib/python3.9/site-packages/evotorch/tools/cloning.py:185, in deep_clone(x, otherwise_deepcopy, otherwise_return, otherwise_fail, memo)
    184 if otherwise_deepcopy:
--> 185     result = deepcopy(x, memo=memo)
    186 elif otherwise_return:

File ~/tools/lib/python3.9/copy.py:161, in deepcopy(x, memo, _nil)
    160 if reductor is not None:
--> 161     rv = reductor(4)
    162 else:

TypeError: cannot pickle 'torch._C.Generator' object

The above exception was the direct cause of the following exception:

TypeError                                 Traceback (most recent call last)
Cell In[497], line 15
     13 searcher = SNES(p, stdev_init=5)
     14 logger = StdOutLogger(searcher)
---> 15 searcher.step()

File ~/python/evotorch/lib/python3.9/site-packages/evotorch/algorithms/searchalgorithm.py:390, in SearchAlgorithm.step(self)
    387 if self._first_step_datetime is None:
    388     self._first_step_datetime = datetime.now()
--> 390 self._step()
    391 self._steps_count += 1
    392 self.update_status({"iter": self._steps_count})

File ~/python/evotorch/lib/python3.9/site-packages/evotorch/algorithms/distributed/gaussian.py:355, in GaussianSearchAlgorithm._step_non_distributed(self)
    350         self._population = SolutionBatch.cat(populations)
    352 if self._first_iter:
    353     # If we are computing the first generation, we just sample from our distribution and evaluate
    354     # the solutions.
--> 355     fill_and_eval_pop()
    356     self._first_iter = False
    357 else:
    358     # If we are computing next generations, then we need to compute the gradients of the last
    359     # generation, sample a new population, and evaluate the new population's solutions.

File ~/python/evotorch/lib/python3.9/site-packages/evotorch/algorithms/distributed/gaussian.py:296, in GaussianSearchAlgorithm._step_non_distributed.<locals>.fill_and_eval_pop()
    293     self._distribution.sample(out=self._population.access_values(), generator=self.problem)
    295     # Finally, here, the solutions are evaluated.
--> 296     self.problem.evaluate(self._population)
    297 else:
    298     # If num_interactions is not None, then this means that we have a threshold for the number
    299     # of simulator interactions to reach before declaring the phase of sampling complete.
   (...)
    304     # Therefore, to properly count the simulator interactions we made during this generation, we need
    305     # to get the interaction count before starting our sampling and evaluation operations.
    306     first_num_interactions = self.problem.status.get("total_interaction_count", 0)

File ~/python/evotorch/lib/python3.9/site-packages/evotorch/core.py:2386, in Problem.evaluate(self, x)
   2380 else:
   2381     raise TypeError(
   2382         f"The method `evaluate(...)` expected a Solution or a SolutionBatch as its argument."
   2383         f" However, the received object is {repr(x)}, which is of type {repr(type(x))}."
   2384     )
-> 2386 self._parallelize()
   2388 if self.is_main:
   2389     self.before_eval_hook(batch)

File ~/python/evotorch/lib/python3.9/site-packages/evotorch/core.py:1880, in Problem._parallelize(self)
   1878     actors = [EvaluationActor.remote(self, i, all_seeds[i], remote_states[i]) for i in range(number_of_actors)]
   1879 else:
-> 1880     actors = [
   1881         EvaluationActor.options(**config_per_actor).remote(self, i, all_seeds[i], remote_states[i])
   1882         for i in range(number_of_actors)
   1883     ]
   1885 self._actors = actors
   1886 self._actor_pool = ActorPool(self._actors)

File ~/python/evotorch/lib/python3.9/site-packages/evotorch/core.py:1881, in <listcomp>(.0)
   1878     actors = [EvaluationActor.remote(self, i, all_seeds[i], remote_states[i]) for i in range(number_of_actors)]
   1879 else:
   1880     actors = [
-> 1881         EvaluationActor.options(**config_per_actor).remote(self, i, all_seeds[i], remote_states[i])
   1882         for i in range(number_of_actors)
   1883     ]
   1885 self._actors = actors
   1886 self._actor_pool = ActorPool(self._actors)

File ~/python/evotorch/lib/python3.9/site-packages/ray/actor.py:639, in ActorClass.options.<locals>.ActorOptionWrapper.remote(self, *args, **kwargs)
    638 def remote(self, *args, **kwargs):
--> 639     return actor_cls._remote(args=args, kwargs=kwargs, **updated_options)

File ~/python/evotorch/lib/python3.9/site-packages/ray/util/tracing/tracing_helper.py:387, in _tracing_actor_creation.<locals>._invocation_actor_class_remote_span(self, args, kwargs, *_args, **_kwargs)
    385 if not _is_tracing_enabled():
    386     assert "_ray_trace_ctx" not in kwargs
--> 387     return method(self, args, kwargs, *_args, **_kwargs)
    389 class_name = self.__ray_metadata__.class_name
    390 method_name = "__init__"

File ~/python/evotorch/lib/python3.9/site-packages/ray/actor.py:968, in ActorClass._remote(self, args, kwargs, **actor_options)
    958         func_name = meta.actor_creation_function_descriptor.function_name
    959     meta.actor_creation_function_descriptor = (
    960         cross_language._get_function_descriptor_for_actor_method(
    961             meta.language,
   (...)
    965         )
    966     )
--> 968 actor_id = worker.core_worker.create_actor(
    969     meta.language,
    970     meta.actor_creation_function_descriptor,
    971     creation_args,
    972     max_restarts,
    973     max_task_retries,
    974     resources,
    975     actor_placement_resources,
    976     max_concurrency,
    977     detached,
    978     name if name is not None else "",
    979     namespace if namespace is not None else "",
    980     is_asyncio,
    981     # Store actor_method_cpu in actor handle's extension data.
    982     extension_data=str(actor_method_cpu),
    983     serialized_runtime_env_info=serialized_runtime_env_info or "{}",
    984     concurrency_groups_dict=concurrency_groups_dict or dict(),
    985     max_pending_calls=max_pending_calls,
    986     scheduling_strategy=scheduling_strategy,
    987 )
    989 if _actor_launch_hook:
    990     _actor_launch_hook(
    991         meta.actor_creation_function_descriptor, resources, scheduling_strategy
    992     )

File python/ray/_raylet.pyx:1964, in ray._raylet.CoreWorker.create_actor()

File python/ray/_raylet.pyx:1969, in ray._raylet.CoreWorker.create_actor()

File python/ray/_raylet.pyx:407, in ray._raylet.prepare_args_and_increment_put_refs()

File python/ray/_raylet.pyx:398, in ray._raylet.prepare_args_and_increment_put_refs()

File python/ray/_raylet.pyx:449, in ray._raylet.prepare_args_internal()

TypeError: Could not serialize the argument <evotorch.core.Problem object at 0x2af78f01d0a0> for a task or actor evotorch.core.EvaluationActor.__init__. Check https://docs.ray.io/en/master/ray-core/objects/serialization.html#troubleshooting for more information.

Example running problem.

When I run the A black-box optimization example, it always shows information as :

[2023-07-10 16:16:21] INFO     <29632> evotorch.core: Instance of `Problem` (id:139776352151312) -- The `dtype` for the problem's decision variables is set as torch.float32
[2023-07-10 16:16:21] INFO     <29632> evotorch.core: Instance of `Problem` (id:139776352151312) -- `eval_dtype` (the dtype of the fitnesses and evaluation data) is set as torch.float32
[2023-07-10 16:16:21] INFO     <29632> evotorch.core: Instance of `Problem` (id:139776352151312) -- The `device` of the problem is set as cpu
[2023-07-10 16:16:21] INFO     <29632> evotorch.core: Instance of `Problem` (id:139776352151312) -- The number of actors that will be allocated for parallelized evaluation is 0

Are there any parameters not properly set? How can I remove this? Thanks.

solving complex nonlinear optimization with evotorch

I have this complex nonlinear optimization problem which I would like to approach with evotorch. I tried to get some clues from the examples but my use case was slightly different.

My first question concerns the bounds:
How do I specify the bounds for each parameter since certain parameters cannot exceed certain bounds.
How do I parallelize the runs? It takes too long for about 5000 iterations
Which solver would be best for my problem. Currently I use SNES.

My example is below. Thanks.

import numpy as np
import torch
from evotorch import Problem
from evotorch.algorithms import SNES
from evotorch.logging import StdOutLogger


# Load in data
F = torch.tensor([1.0000e-01, 1.3000e-01, 1.6900e-01, 2.2000e-01, 2.8600e-01, 3.7100e-01,
        4.8300e-01, 6.2700e-01, 8.1600e-01, 1.0600e+00, 1.3800e+00, 1.7900e+00,
        2.3300e+00, 3.0300e+00, 3.9400e+00, 5.1200e+00, 6.6500e+00, 8.6500e+00,
        1.1200e+01, 1.4600e+01, 1.9000e+01, 2.4700e+01, 3.2100e+01, 4.1800e+01,
        5.4300e+01, 7.0600e+01, 9.1700e+01, 1.1900e+02, 1.5500e+02, 2.0200e+02,
        2.6200e+02, 3.4100e+02, 4.4300e+02, 5.7600e+02, 7.4800e+02, 9.7300e+02,
        1.2600e+03, 1.6400e+03, 2.1400e+03, 2.7800e+03, 3.6100e+03, 4.7000e+03,
        6.1000e+03, 7.9400e+03, 1.0300e+04, 1.3400e+04, 1.7400e+04, 2.2700e+04,
        2.9500e+04, 3.8300e+04, 4.9800e+04, 6.4700e+04, 8.4200e+04, 1.0900e+05],
       dtype=torch.float64)

Z = torch.tensor([45.1000-1.0900j, 47.5000-1.4300j, 46.8000-1.7700j, 46.2000-2.2900j,
        46.2000-2.9700j, 47.2000-3.8000j, 47.0000-4.8500j, 45.1000-5.9900j,
        45.8000-7.3300j, 42.3000-9.0500j, 42.6000-10.2000j, 36.5000-10.8000j,
        34.5000-11.2000j, 32.1000-10.2000j, 30.0000-9.1800j, 29.4000-8.0000j,
        27.3000-6.6400j, 26.7000-5.1800j, 25.3000-4.1200j, 25.4000-3.2600j,
        25.2000-2.5100j, 24.9000-1.9400j, 24.9000-1.6400j, 25.4000-1.3500j,
        25.5000-1.2400j, 24.8000-1.1000j, 24.7000-1.0300j, 23.9000-1.0400j,
        25.2000-1.1000j, 24.9000-1.2700j, 25.0000-1.4600j, 25.4000-1.6500j,
        24.4000-1.9800j, 24.5000-2.3400j, 24.5000-2.9100j, 23.8000-3.4700j,
        22.9000-4.1300j, 22.3000-4.9100j, 20.9000-5.6600j, 20.3000-6.0300j,
        18.4000-6.9600j, 17.6000-7.2400j, 16.5000-7.7400j, 14.3000-7.4200j,
        12.7000-7.1700j, 11.2000-6.7600j,  9.8500-5.8900j,  8.6800-5.3800j,
         7.9200-4.5300j,  7.2000-3.8300j,  6.8100-3.2000j,  6.6500-2.6700j,
         6.1100-2.1600j,  5.8600-1.7700j], dtype=torch.complex128)

sigma = torch.tensor([45.1132, 47.5215, 46.8335, 46.2567, 46.2954, 47.3527, 47.2496, 45.4960,
        46.3829, 43.2573, 43.8041, 38.0643, 36.2724, 33.6816, 31.3731, 30.4690,
        28.0959, 27.1978, 25.6333, 25.6084, 25.3247, 24.9755, 24.9539, 25.4359,
        25.5301, 24.8244, 24.7215, 23.9226, 25.2240, 24.9324, 25.0426, 25.4535,
        24.4802, 24.6115, 24.6722, 24.0516, 23.2694, 22.8341, 21.6528, 21.1767,
        19.6724, 19.0310, 18.2252, 16.1104, 14.5842, 13.0820, 11.4767, 10.2121,
         9.1240,  8.1553,  7.5244,  7.1660,  6.4806,  6.1215],
       dtype=torch.float64) 



p0 = torch.tensor([5, 0.000103, 1, 20, 0.001, 20])


# Define bounds such that parameter in inx 2 is between 0.1 and 1, while parameters 1 and 4 are between 1e-9 and 1e-1
lb = np.full((len(p0),),1e-15)
lb[1] = 1e-9
lb[2] = 0.1
lb[4] = 1e-9
ub = np.full((len(p0),),1e15)
ub[1] = 1e-1
ub[2] = 1.01
ub[4] = 1e-1



# Define model
def fun(p, x):
    w = 2*torch.pi*x
    s = 1j*w
    Rs = p[0]
    Qh = p[1]
    nh = p[2]
    Rct = p[3]
    C1 = p[4]
    R1 = p[5]
    Y1 = s*C1 + 1/R1
    Z1 = 1/Y1
    Zct = Rct + Z1
    Ydl = (s**nh)*Qh
    Yin = Ydl + 1/Zct
    Zin = 1/Yin
    Z = Rs + Zin
    return torch.concat((Z.real, Z.imag),dim = 0)


# Define loss function
def obj_fun(p, x, y, yerr):
    ndata = len(x)
    dof = (2*ndata-(len(p)))
    y_concat = torch.concat([y.real, y.imag], dim = 0)
    sigma = torch.concat([yerr,yerr], dim = 0)
    y_model = fun(p, x)
    chi_sqr = (1/dof)*(torch.sum(torch.abs((1/sigma**2) * (y_concat - y_model)**2)))
    return (chi_sqr)


# Define problem
problem = Problem(
  "min",
  lambda p0: obj_fun(p0, F, Z, sigma),
  initial_bounds=[lb, ub],
  solution_length=len(p0),
)



searcher = SNES(problem, popsize=1000, stdev_init=2.0)
_ = StdOutLogger(searcher, interval=50)

searcher.run(num_generations=5000)


# popt expected  = 5.2658e+00, 7.4640e-06, 8.2708e-01, 1.9907e+01, 3.4077e-03, 2.1928e+01

# Results
# There seems to be no change in the loss
#          iter : 50
#     mean_eval : 3.1693422474173666e+25
# pop_best_eval : 3.169341555664464e+25
#   median_eval : 3.169341555664464e+25
#     best_eval : 3.169341555664464e+25
#    worst_eval : 7.474293084492361e+26

#          iter : 100
#     mean_eval : 3.1693422474173666e+25
# pop_best_eval : 3.169341555664464e+25
#   median_eval : 3.169341555664464e+25
#     best_eval : 3.169341555664464e+25
#    worst_eval : 7.474293084492361e+26

Documentation of using stateful nn.Module classes in neuroevolution

Neuroevolution classes support stateful nn.Module instances. It is assumed that a stateful nn.Module instance will maintain its own internal hidden state, which it will reset when module.reset() is called (if this method is defined). In particular, the GymNE class does this at the start of the episode, allowing the application of RNNs, LSTMs and Transformers to Gym environments.

Currently, this feature is not documented. Therefore, we should either add additional documentation to the User Guide/Neuroevolution section, or add a new User Guide/Stateful Neuroevolution section.

Additionally, the string-based network representation also has support for "RecurrentNet" and "LSTMNet" modules, which will provide a module.reset() method. These special strings should also be added to this documentation.

Add better help message when using device="cuda" with Ray actors

When defining a Problem, if the user specifies device="cuda", num_actors=2 (as an example), but does not specify num_gpus_per_actor, the following error results from each actor which is not fully clear on what's wrong:

RuntimeError: Attempting to deserialize object on a CUDA device but torch.cuda.is_available() is False. If you are running on a CPU-only machine, please use torch.load with map_location=torch.device('cpu') to map your storages to the CPU.

Such a misconfig should be detected and a more helpful message should be given instead.

When I run a mpc optimization code, it shows: "AttributeError: 'NoneType' object has no attribute 'evals'"

I run multiple rounds without any errors, but the in the last round, it shows "AttributeError: 'NoneType' object has no attribute 'evals'" .
The whole error is:

Output exceeds the [size limit](command:workbench.action.openSettings?%5B%22notebook.output.textLineLimit%22%5D). Open the full output data [in a text editor](command:workbench.action.openLargeOutput?cfd71559-5421-469a-b470-e0a1cf3a17b8)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[28], line 22
     19 k2 = 0.02 # 
     20 k3 = 1.1 # 
---> 22 temp_new, temp_old = run_episode(data, state_dim, action_dim, horizon, k0, k1, k2, k3, rounds, time_steps)

Cell In[27], line 44, in run_episode(offline_states, state_dim, action_dim, horizon, k0, k1, k2, k3, rounds, time_steps)
     41     n_state = n_state.reshape(1, -1)
     42     action_input = n_action.reshape(1,-1)
---> 44 action = do_planning(n_state, 
     45                     action_input,
     46                     bias, 
     47                     input_length=input_length, 
     48                     horizon=horizon, 
     49                     action_dim=action_dim,
     50                     k0 = k0,
     51                     k1 = k1,
     52                     k2 = k2,
     53                     k3 = k3)
     55 action = np.clip(action, 0.0, 100.0) 
     56 n_action = action.reshape(1, -1) # (1, action_dim)

Cell In[10], line 18, in do_planning(state, hist_action, bias, input_length, horizon, action_dim, k0, k1, k2, k3)
      4 searcher = CEM(
      5     problem,
      6     stdev_init=10.0,
   (...)
      9     stdev_max_change=5.0,
     10 )
     11 # searcher = SNES(
     12 #     problem,
     13 #     radius_init=10,
   (...)
     16 #     # stdev_max_change=0.2,
     17 # )
---> 18 searcher.run(20)  # run for this many generations
     20 # new_actions = searcher.status["best"].values.reshape(horizon, action_dim).clone()
     22 action_candidate = searcher.status["best"].values.clone().numpy()

File [~/anaconda3/envs/dpc/lib/python3.10/site-packages/evotorch/algorithms/searchalgorithm.py:425](https://file+.vscode-resource.vscode-cdn.net/media/lk/lksgcc/DL_lk/202205_RZ_GAN%E6%A8%A1%E5%9E%8B/model/EvoOpt/~/anaconda3/envs/dpc/lib/python3.10/site-packages/evotorch/algorithms/searchalgorithm.py:425), in SearchAlgorithm.run(self, num_generations, reset_first_step_datetime)
    422     self.reset_first_step_datetime()
    424 for _ in range(int(num_generations)):
--> 425     self.step()
    427 if len(self._end_of_run_hook) >= 1:
    428     self._end_of_run_hook(dict(self.status))

File [~/anaconda3/envs/dpc/lib/python3.10/site-packages/evotorch/algorithms/searchalgorithm.py:390](https://file+.vscode-resource.vscode-cdn.net/media/lk/lksgcc/DL_lk/202205_RZ_GAN%E6%A8%A1%E5%9E%8B/model/EvoOpt/~/anaconda3/envs/dpc/lib/python3.10/site-packages/evotorch/algorithms/searchalgorithm.py:390), in SearchAlgorithm.step(self)
    387 if self._first_step_datetime is None:
    388     self._first_step_datetime = datetime.now()
--> 390 self._step()
    391 self._steps_count += 1
    392 self.update_status({"iter": self._steps_count})

File [~/anaconda3/envs/dpc/lib/python3.10/site-packages/evotorch/algorithms/distributed/gaussian.py:354](https://file+.vscode-resource.vscode-cdn.net/media/lk/lksgcc/DL_lk/202205_RZ_GAN%E6%A8%A1%E5%9E%8B/model/EvoOpt/~/anaconda3/envs/dpc/lib/python3.10/site-packages/evotorch/algorithms/distributed/gaussian.py:354), in GaussianSearchAlgorithm._step_non_distributed(self)
    349         self._population = SolutionBatch.cat(populations)
    351 if self._first_iter:
    352     # If we are computing the first generation, we just sample from our distribution and evaluate
    353     # the solutions.
--> 354     fill_and_eval_pop()
    355     self._first_iter = False
    356 else:
    357     # If we are computing next generations, then we need to compute the gradients of the last
    358     # generation, sample a new population, and evaluate the new population's solutions.

File [~/anaconda3/envs/dpc/lib/python3.10/site-packages/evotorch/algorithms/distributed/gaussian.py:295](https://file+.vscode-resource.vscode-cdn.net/media/lk/lksgcc/DL_lk/202205_RZ_GAN%E6%A8%A1%E5%9E%8B/model/EvoOpt/~/anaconda3/envs/dpc/lib/python3.10/site-packages/evotorch/algorithms/distributed/gaussian.py:295), in GaussianSearchAlgorithm._step_non_distributed..fill_and_eval_pop()
    292     self._distribution.sample(out=self._population.access_values(), generator=self.problem)
    294     # Finally, here, the solutions are evaluated.
--> 295     self.problem.evaluate(self._population)
    296 else:
    297     # If num_interactions is not None, then this means that we have a threshold for the number
    298     # of simulator interactions to reach before declaring the phase of sampling complete.
   (...)
    303     # Therefore, to properly count the simulator interactions we made during this generation, we need
    304     # to get the interaction count before starting our sampling and evaluation operations.
    305     first_num_interactions = self.problem.status.get("total_interaction_count", 0)

File [~/anaconda3/envs/dpc/lib/python3.10/site-packages/evotorch/core.py:2403](https://file+.vscode-resource.vscode-cdn.net/media/lk/lksgcc/DL_lk/202205_RZ_GAN%E6%A8%A1%E5%9E%8B/model/EvoOpt/~/anaconda3/envs/dpc/lib/python3.10/site-packages/evotorch/core.py:2403), in Problem.evaluate(self, x)
   2400 if self.is_main:
   2401     self._after_eval_status = {}
-> 2403     best_and_worst = self._get_best_and_worst(batch)
   2404     if best_and_worst is not None:
   2405         self._after_eval_status.update(best_and_worst)

File [~/anaconda3/envs/dpc/lib/python3.10/site-packages/torch/utils/_contextlib.py:115](https://file+.vscode-resource.vscode-cdn.net/media/lk/lksgcc/DL_lk/202205_RZ_GAN%E6%A8%A1%E5%9E%8B/model/EvoOpt/~/anaconda3/envs/dpc/lib/python3.10/site-packages/torch/utils/_contextlib.py:115), in context_decorator..decorate_context(*args, **kwargs)
    112 @functools.wraps(func)
    113 def decorate_context(*args, **kwargs):
    114     with ctx_factory():
--> 115         return func(*args, **kwargs)

File [~/anaconda3/envs/dpc/lib/python3.10/site-packages/evotorch/core.py:2232](https://file+.vscode-resource.vscode-cdn.net/media/lk/lksgcc/DL_lk/202205_RZ_GAN%E6%A8%A1%E5%9E%8B/model/EvoOpt/~/anaconda3/envs/dpc/lib/python3.10/site-packages/evotorch/core.py:2232), in Problem._get_best_and_worst(self, batch)
   2226         self._worst[i_obj] = batch[worst_sln_index].clone()
   2228 if len(senses) == 1:
   2229     return dict(
   2230         best=self._best[0],
...
   2234     )
   2235 else:
   2236     return {"best": self._best, "worst": self._worst}

AttributeError: 'NoneType' object has no attribute 'evals'

I use CEM to solve my problem, the parameters are set as:
searcher = CEM(
problem,
stdev_init=10.0,
popsize=50, # population size
parenthood_ratio=0.2,
stdev_max_change=5.0,
)

searcher.run(20)

super().init(
objective_sense="min",
initial_bounds=(50.0, 100.0),
solution_length=(horizon * action_dim), # action的dim=4
# device='cuda:0'
)

the actions should be in [0, 100], So I set the initial_bounds as (50.0, 100.0).

cma initialization problem

When I am using CMAES searcher, the following problem occurs:

Traceback (most recent call last):
  File "/Users/haohaomiao/codefields/EvoTorch/test.py", line 11, in <module>
    searcher = CMAES(problem, stdev_init = 10)
  File "/Users/haohaomiao/anaconda3/envs/EvoTorch/lib/python3.10/site-packages/evotorch/algorithms/cmaes.py", line 365, in __init__
    self.decompose_C_freq = max(1, int(1 / np.floor(10 * d * (self.c_1.cpu() + self.c_mu.cpu()))))
OverflowError: cannot convert float infinity to integer

The dimension of my problem is 1000. 1000 is not a big number so maybe an improvement is needed.

CMAES "can't convert cuda:0 device type tensor to numpy" error

Hi guys,

Your work is awesome! 🏆

I am running into the following error when trying to run your example script with CMAES instead of SNES.

TypeError: can't convert cuda:0 device type tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.

Here's the script:

#CMA-ES Test
from evotorch import Problem
from evotorch.algorithms import SNES, CMAES
from evotorch.logging import StdOutLogger, PandasLogger
import math
import matplotlib.pyplot as plt
import torch

# Declare the objective function
def rastrigin(x: torch.Tensor) -> torch.Tensor:
    A = 10
    (_, n) = x.shape
    return A * n + torch.sum((x**2) - A * torch.cos(2 * math.pi * x), 1)

# Declare the problem
problem = Problem(
    "min",
    rastrigin,
    initial_bounds=(-5.12, 5.12),
    solution_length=100,
    vectorized=True,
    device="cuda:0"  # enable this line if you wish to use GPU
)

# Initialize the SNES algorithm to solve the problem
searcher = CMAES(problem, popsize=2000, stdev_init=10.0)

# Initialize a standard output logger, and a pandas logger
#_ = StdOutLogger(searcher, interval=10)
pandas_logger = PandasLogger(searcher)
searcher.run(5000)

Any help would be appreciated!

Best,

Gym 0.26.0+ compatibility

Recent changes to the gym library introduced by version 0.26.0 cause various issues. The following have been observed:

  • GymNE.visualize(...) no longer renders. This can be observed in examples/notebooks/Gym_Experiments_with_PGPE_and_CoSyNE.ipynb. Similarly the gym changes prevent any rendering from examples/scripts/rl_enjoy.py. In neither case is an exception thrown.
  • gym.make(...) can throw exceptions breaking the MPC example. This can be observed in examples/notebooks/Model_Predictive_Control_With_CEM/reacher_mpc.ipynb:
TypeError: __init__() got an unexpected keyword argument 'new_step_api'

To reproduce these issues:

  • git clone https://github.com/nnaisense/evotorch.git
  • cd evotorch && conda env create -f env.yml
  • conda activate evotorch && pip install gym <--- this should install 0.26.1
  • jupyter lab
    And then run the example notebooks listed above.

Possibly, there are other compatibility issues. We can continue to document them here as we find them.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.