diff --git a/Makefile b/Makefile deleted file mode 100644 index 00aff1a..0000000 --- a/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -init: - pip install -r requirements.txt - -test: - python -m unittest discover - -install_develop: - python setup.py develop - -install: - python setup.py install - -documentation: - sphinx-apidoc -e -f samplepackage -o doc/ diff --git a/resources/documentation.md b/README.md similarity index 99% rename from resources/documentation.md rename to README.md index 836991c..5bbcf0d 100644 --- a/resources/documentation.md +++ b/README.md @@ -1,201 +1,201 @@ -                ![docs_title_logo](docs_title_logo.png) +                ![docs_title_logo](./resources/docs_title_logo.png) # A Hyper-Parameter Optimization Toolbox
## What is Hyppopy? Hyppopy is a python toolbox for blackbox optimization. It's purpose is to offer a unified and easy to use interface to a collection of solver libraries. Solver Hyppopy is providing are: * [Hyperopt](http://hyperopt.github.io/hyperopt/) * [Optunity](https://optunity.readthedocs.io/en/latest/user/index.html) * [Optuna](https://optuna.org/) * [BayesianOptimization](https://github.com/fmfn/BayesianOptimization) * Randomsearch Solver * Gridsearch Solver ## Installation 1. clone the [Hyppopy](http:\\github.com) project from Github 2. (create a virtual environment), open a console (with your activated virtual env) and go to the hyppopy root folder 3. type: ```$ python setup.py install``` ## How to use Hyppopy? #### The HyppopyProject class The HyppopyProject class takes care all settings necessary for the solver and your workflow. To setup a HyppopyProject instance we can use a nested dictionary or the classes memberfunctions respectively. ```python # Import the HyppopyProject class from hyppopy.HyppopyProject import HyppopyProject # Create a nested dict with a section hyperparameter. We define a 2 dimensional # hyperparameter space with a numerical dimension named myNumber of type float and # a uniform sampling. The second dimension is a categorical parameter of type string. config = { "hyperparameter": { "myNumber": { "domain": "uniform", "data": [0, 100], "type": "float" }, "myOption": { "domain": "categorical", "data": ["a", "b", "c"], "type": "str" } } }} # Create a HyppopyProject instance and pass the config dict to # the constructor. Alternatively one can use set_config method. project = HyppopyProject(config=config) # To demonstrate the second option we clear the project project.clear() # and add the parameter again using the member function add_hyperparameter project.add_hyperparameter(name="myNumber", domain="uniform", data=[0, 100], dtype="float") project.add_hyperparameter(name="myOption", domain="categorical", data=["a", "b", "c"], dtype="str") ``` ```python # We might have seen a warning: 'UserWarning: config dict had no # section settings/solver/max_iterations, set default value: 500' # when executing the example above. This is due to the fact that # most solvers need a value for a maximum number of iterations. # To take care of solver settings (there might be more in the future) # one can set a second section called settings. The settings section # again is splitted into a subsection 'solver' and a subsection 'custom'. # When adding max_iterations to the section settings/solver we can change # the number of iterations the solver is doing. All solver except of the # GridsearchSolver make use of the value max_iterations. # The usage of the custom section is demonstrated later. config = { "hyperparameter": { "myNumber": { "domain": "uniform", "data": [0, 100], "type": "float" }, "myOption": { "domain": "categorical", "data": ["a", "b", "c"], "type": "str" } }, "settings": { "solver": { "max_iterations": 500 }, "custom": {} }} project = HyppopyProject(config=config) ``` The settings added are automatically converted to a class member with a prefix_ where prefix is the name of the subsection. One can make use of this feature to build custom workflows by adding params to the custom section. More interesting is this feature when developing your own solver. ```python from hyppopy.HyppopyProject import HyppopyProject # Creating a HyppopyProject instance project = HyppopyProject() project.add_hyperparameter(name="x", domain="uniform", data=[-10, 10], dtype="float") project.add_hyperparameter(name="y", domain="uniform", data=[-10, 10], dtype="float") project.add_settings(section="solver", name="max_iterations", value=300) project.add_settings(section="custom", name="my_param1", value=True) project.add_settings(section="custom", name="my_param2", value=42) print("What is max_iterations value? {}".format(project.solver_max_iterations)) if project.custom_my_param1: print("What is the answer? {}".format(project.custom_my_param2)) else: print("What is the answer? x") ``` #### The HyppopySolver classes Each solver is a child of the HyppopySolver class. This is only interesting if you're planning to write a new solver, we will discuss this in the section Solver Development. All solvers we can use to optimize our blackbox function are part of the module 'hyppopy.solver'. Below is a list of all solvers available along with their access key in squared brackets. * HyperoptSolver [hyperopt] * OptunitySolver [optunity] * OptunaSolver [optuna] * BayesOptSolver [bayesopt] * RandomsearchSolver [randomsearch] * GridsearchSolver [gridsearch] There are two options to get a solver, we can import directly from the hyppopy.solver package or we use the SolverPool class. We look into both options by optimizing a simple function, starting with the direct import case. ```python # Import the HyppopyProject class from hyppopy.HyppopyProject import HyppopyProject # Import the HyperoptSolver class, in this case wh use Hyperopt from hyppopy.solver.HyperoptSolver import HyperoptSolver # Our function to optimize def my_loss_func(x, y): return x**2+y**2 # Creating a HyppopyProject instance project = HyppopyProject() project.add_hyperparameter(name="x", domain="uniform", data=[-10, 10], dtype="float") project.add_hyperparameter(name="y", domain="uniform", data=[-10, 10], dtype="float") project.add_settings(section="solver", name="max_iterations", value=300) # create a solver instance solver = HyperoptSolver(project) # pass the loss function to the solver solver.blackbox = my_loss_func # run the solver solver.run() df, best = solver.get_results() print("\n") print("*"*100) print("Best Parameter Set:\n{}".format(best)) print("*"*100) ``` The SolverPool is a class keeping track of all solver classes. We have several options to ask the SolverPool for the desired solver. We can add an option called use_solver to our settings/custom section or to the project instance respectively, or we can use the solver access key (see solver listing above) to ask for the solver directly. ```python # import the SolverPool class from hyppopy.SolverPool import SolverPool # Import the HyppopyProject class from hyppopy.HyppopyProject import HyppopyProject # Our function to optimize def my_loss_func(x, y): return x**2+y**2 # Creating a HyppopyProject instance project = HyppopyProject() project.add_hyperparameter(name="x", domain="uniform", data=[-10, 10], dtype="float") project.add_hyperparameter(name="y", domain="uniform", data=[-10, 10], dtype="float") project.add_settings(section="solver", name="max_iterations", value=300) project.add_settings(section="custom", name="use_solver", value="hyperopt") # create a solver instance. The SolverPool class is a singleton # and can be used without instanciating. It looks in the project # instance for the use_solver option and returns the correct solver. solver = SolverPool.get(project=project) # Another option without the usage of the use_solver field would be: # solver = SolverPool.get(solver_name='hyperopt', project=project) # pass the loss function to the solver solver.blackbox = my_loss_func # run the solver solver.run() df, best = solver.get_results() print("\n") print("*"*100) print("Best Parameter Set:\n{}".format(best)) print("*"*100) ``` \ No newline at end of file diff --git a/README.rst b/README.rst deleted file mode 100644 index a08c288..0000000 --- a/README.rst +++ /dev/null @@ -1,4 +0,0 @@ -Hyppopy -======================== - -The friendly Hyppo (HYPer-Parameter-Optimizer) helping you to find your inner blackbox optimum. diff --git a/hyppopy/__init__.py b/hyppopy/__init__.py index 651862e..d4d866d 100644 --- a/hyppopy/__init__.py +++ b/hyppopy/__init__.py @@ -1 +1 @@ -__version__ = '0.3.4.1' +__version__ = '0.4.0.0' diff --git a/hyppopy/tests/test_optunasolver.py b/hyppopy/tests/test_optunasolver.py new file mode 100644 index 0000000..f22e526 --- /dev/null +++ b/hyppopy/tests/test_optunasolver.py @@ -0,0 +1,66 @@ +# DKFZ +# +# +# Copyright (c) German Cancer Research Center, +# Division of Medical and Biological Informatics. +# All rights reserved. +# +# This software is distributed WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. +# +# See LICENSE.txt or http://www.mitk.org for details. +# +# Author: Sven Wanner (s.wanner@dkfz.de) + +import unittest +import matplotlib.pylab as plt + +from hyppopy.solver.OptunaSolver import * +from hyppopy.VirtualFunction import VirtualFunction +from hyppopy.HyppopyProject import HyppopyProject + + +class OptunaSolverTestSuite(unittest.TestCase): + + def setUp(self): + pass + + def test_solver_complete(self): + config = { + "hyperparameter": { + "axis_00": { + "domain": "normal", + "data": [300, 800], + "type": "float" + }, + "axis_01": { + "domain": "normal", + "data": [-1, 1], + "type": "float" + }, + "axis_02": { + "domain": "uniform", + "data": [0, 10], + "type": "float" + } + }, + "settings": { + "solver": {"max_iterations": 800}, + "custom": {} + }} + + project = HyppopyProject(config) + solver = OptunaSolver(project) + vfunc = VirtualFunction() + vfunc.load_default() + solver.blackbox = vfunc + solver.run(print_stats=False) + df, best = solver.get_results() + self.assertTrue(570 < best['axis_00'] < 590) + self.assertTrue(0.1 < best['axis_01'] < 0.8) + self.assertTrue(4.5 < best['axis_02'] < 6) + + +if __name__ == '__main__': + unittest.main() diff --git a/requirements.txt b/requirements.txt index d5e39f9..5808742 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,15 +1,12 @@ -dicttoxml>=1.7.4 -xmltodict>=0.11.0 -hyperopt>=0.1.1 -Optunity>=1.1.1 -numpy>=1.16.0 -matplotlib>=3.0.2 -scikit-learn>=0.20.2 -scipy>=1.2.0 -Sphinx>=1.8.3 -xmlrunner>=1.7.7 -Yapsy>=1.11.223 -pandas>=0.24.1 -seaborn>=0.9.0 +bayesian-optimization>=1.0.1 deap>=1.2.2 -bayesian-optimization>=1.0.1 \ No newline at end of file +hyperopt>=0.1.2 +hyppopy>=0.4.0.0 +matplotlib>=3.0.3 +numpy>=1.16.2 +optuna>=0.9.0 +Optunity>=1.1.1 +pandas>=0.24.2 +pytest>=4.3.1 +scikit-learn>=0.20.3 +scipy>=1.2.1 diff --git a/setup.py b/setup.py index db41632..ab56481 100644 --- a/setup.py +++ b/setup.py @@ -1,63 +1,57 @@ -# -*- coding: utf-8 -*- - import os from setuptools import setup, find_packages -with open('README.rst') as f: +with open('README.md') as f: readme = f.read() with open('LICENSE') as f: license = f.read() -VERSION = "0.3.4.1" +VERSION = "0.4.0.0" ROOT = os.path.dirname(os.path.realpath(__file__)) new_init = [] with open(os.path.join(ROOT, *("hyppopy", "__init__.py")), "r") as infile: for line in infile: new_init.append(line) for n in range(len(new_init)): if new_init[n].startswith("__version__"): split = line.split("=") new_init[n] = "__version__ = '" + VERSION + "'\n" with open(os.path.join(ROOT, *("hyppopy", "__init__.py")), "w") as outfile: outfile.writelines(new_init) setup( name='hyppopy', version=VERSION, description='Hyper-Parameter Optimization Toolbox for Blackboxfunction Optimization', long_description=readme, # if you want, put your own name here # (this would likely result in people sending you emails) author='Sven Wanner', author_email='s.wanner@dkfz.de', url='', license=license, - packages=find_packages(exclude=('*test*', 'doc')), + packages=find_packages(exclude=('tests', 'doc')), package_data={ - 'hyppopy.plugins': ['*.yapsy-plugin'] }, # the requirements to install this project. # Since this one is so simple this is empty. install_requires=[ - 'dicttoxml>=1.7.4', - 'xmltodict>=0.11.0', - 'hyperopt>=0.1.1', - 'Optunity>=1.1.1', - 'numpy>=1.16.0', - 'matplotlib>=3.0.2', - 'scikit-learn>=0.20.2', - 'scipy>=1.2.0', - 'Sphinx>=1.8.3', - 'xmlrunner>=1.7.7', - 'Yapsy>=1.11.223', - 'pandas>=0.24.1', - 'seaborn>=0.9.0', + 'bayesian-optimization>=1.0.1', 'deap>=1.2.2', - 'bayesian-optimization>=1.0.1' + 'hyperopt>=0.1.2', + 'hyppopy>=0.4.0.0', + 'matplotlib>=3.0.3', + 'numpy>=1.16.2', + 'optuna>=0.9.0', + 'Optunity>=1.1.1', + 'pandas>=0.24.2', + 'pytest>=4.3.1', + 'scikit-learn>=0.20.3', + 'scipy>=1.2.1' ], )