Repository: facebookresearch/nevergrad

Issue:
Nevergrad 0.12 introduces dependency on ax-platform and torch, which take a lot of space
## Summary

Since the latest release (0.12.0) from earlier today, Nevergrad has a new dependency on ax-platform.
Ax-platform itself depends on botorch, which depends on torch, which depends on Nvidia libraries (CUDA, cuDNN) that take a lot of space (several GB), a lot of time to install and are unnecessary in most cases. 
As a result, a minimal default installation of Nevergrad has increased in size by more than 3GB compared to the previous release, which is an issue for running in small containers.
This new dependency might also increase the risk of dependency conflicts with other libraries.

Is the dependency on ax-platform necessary?
Can it be made optional, or installed without torch?

## Steps to reproduce

Install nevergrad==0.12 with pip in a clean virtual environment. 
Install nevergrad==0.11 with pip in another clean virtual environment.
There is a difference of more than 3GB in the amount of memory required for each environment.



Discussion:

Resolving patch:
diff --git a/nevergrad/optimization/optimizerlib.py b/nevergrad/optimization/optimizerlib.py
--- a/nevergrad/optimization/optimizerlib.py
+++ b/nevergrad/optimization/optimizerlib.py
@@ -440,8 +440,8 @@ class ParametrizedOnePlusOne(base.ConfiguredOptimizer):
 
     Notes
     -----
-    After many papers advocared the mutation rate 1/d in the discrete (1+1) for the discrete case,
-    `it was proposed <https://arxiv.org/abs/1606.05551>`_ to use of a randomly
+    After many papers advocated the mutation rate 1/d in the discrete (1+1) for the discrete case,
+    `it was proposed <https://arxiv.org/abs/1606.05551>`_ to use a randomly
     drawn mutation rate. `Fast genetic algorithms <https://arxiv.org/abs/1703.03334>`_ are based on a similar idea
     These two simple methods perform quite well on a wide range of problems.
 
@@ -690,7 +690,7 @@ def _internal_provide_recommendation(self) -> np.ndarray:
 
 class ParametrizedCMA(base.ConfiguredOptimizer):
     """CMA-ES optimizer,
-    This evolution strategy uses a Gaussian sampling, iteratively modified
+    This evolution strategy uses Gaussian sampling, iteratively modified
     for searching in the best directions.
     This optimizer wraps an external implementation: https://github.com/CMA-ES/pycma
 
@@ -1447,6 +1447,8 @@ def enable_pickling(self) -> None:
 class Rescaled(base.ConfiguredOptimizer):
     """Configured optimizer for creating rescaled optimization algorithms.
 
+    By default, scales to sqrt(log(budget)/n_dimensions).
+
     Parameters
     ----------
     base_optimizer: base.OptCls
diff --git a/nevergrad/optimization/recastlib.py b/nevergrad/optimization/recastlib.py
--- a/nevergrad/optimization/recastlib.py
+++ b/nevergrad/optimization/recastlib.py
@@ -10,9 +10,6 @@
 import weakref
 import numpy as np
 from scipy import optimize as scipyoptimize
-import cma
-import pybobyqa  # type: ignore
-from ax import optimize as axoptimize  # type: ignore
 import nevergrad.common.typing as tp
 from nevergrad.parametrization import parameter as p
 from nevergrad.common import errors
@@ -107,11 +104,15 @@ def ax_obj(p):
             # print(f"Iteration with remaining={remaining}")
             options: tp.Dict[str, tp.Any] = {} if weakself.budget is None else {"maxiter": remaining}
             if weakself.method == "BOBYQA":
+                import pybobyqa  # type: ignore
+
                 res = pybobyqa.solve(objective_function, best_x, maxfun=budget, do_logging=False)
                 if res.f < best_res:
                     best_res = res.f
                     best_x = res.x
             elif weakself.method == "AX":
+                from ax import optimize as axoptimize  # type: ignore
+
                 parameters = [
                     {"name": "x" + str(i), "type": "range", "bounds": [0.0, 1.0]}
                     for i in range(weakself.dimension)
@@ -125,7 +126,7 @@ def ax_obj(p):
             elif weakself.method[:5] == "NLOPT":
                 # This is NLOPT, used as in the PCSE simulator notebook.
                 # ( https://github.com/ajwdewit/pcse_notebooks ).
-                import nlopt
+                import nlopt  # type: ignore
 
                 def nlopt_objective_function(*args):
                     try:
@@ -362,6 +363,7 @@ def smac2_obj(p, seed: int = 0):
             #                    best_x = weakself._normalizer.backward(np.asarray(x, dtype=float))
             #
             elif weakself.method == "CmaFmin2":
+                import cma  # type: ignore
 
                 def cma_objective_function(data):
                     # Hopefully the line below does nothing if unbounded and rescales from [0, 1] if bounded.


Test patch: