From 3aaf234698757231ccc7cf72efaa26bb2b3a37f2 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Tue, 11 Jul 2017 18:03:37 +0200 Subject: [PATCH 01/18] Work towards sphinx based documentation --- .gitignore | 1 + docs/Makefile | 20 +++++ docs/_static/custom.css | 3 + docs/api/index.rst | 10 +++ docs/api/minimize_functions.rst | 11 +++ docs/api/utils.rst | 7 ++ docs/conf.py | 177 ++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 28 +++++++ docs/intro.rst | 21 +++++ media/logo.png | Bin 0 -> 18280 bytes skopt/__init__.py | 46 +---------- skopt/utils.py | 1 + 12 files changed, 281 insertions(+), 44 deletions(-) create mode 100644 docs/Makefile create mode 100644 docs/_static/custom.css create mode 100644 docs/api/index.rst create mode 100644 docs/api/minimize_functions.rst create mode 100644 docs/api/utils.rst create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/intro.rst create mode 100644 media/logo.png diff --git a/.gitignore b/.gitignore index 9b039ac..1dcaca0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ dist/ *.egg-info/ .idea/ .cache/ +docs/_build # mac OS users .DS_Store diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..c8aa9b2 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = scikit-optimize +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 0000000..8bbace2 --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,3 @@ +.function { + padding-bottom: 30px; +} diff --git a/docs/api/index.rst b/docs/api/index.rst new file mode 100644 index 0000000..220c154 --- /dev/null +++ b/docs/api/index.rst @@ -0,0 +1,10 @@ +============= +API Reference +============= + +Look at :ref:`minimize-functions`. Check :ref:`utility-functions` + +.. toctree:: + + minimize_functions + utils diff --git a/docs/api/minimize_functions.rst b/docs/api/minimize_functions.rst new file mode 100644 index 0000000..fc1a380 --- /dev/null +++ b/docs/api/minimize_functions.rst @@ -0,0 +1,11 @@ +.. _minimize-functions: + +Top level minimization functions +================================ + +Easy to get started with these functions. They mirror the ``scipy.optimize`` +API. + +.. autofunction:: skopt.dummy_minimize + +.. autofunction:: skopt.gp_minimize diff --git a/docs/api/utils.rst b/docs/api/utils.rst new file mode 100644 index 0000000..a649d4c --- /dev/null +++ b/docs/api/utils.rst @@ -0,0 +1,7 @@ +.. _utility-functions: + +Utilities +========= + +.. automodule:: skopt.utils + :members: diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..91da377 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# scikit-optimize documentation build configuration file, created by +# sphinx-quickstart on Tue Jul 11 16:28:14 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx.ext.autodoc', + #'sphinx.ext.autosummary', + 'sphinx.ext.mathjax', + 'sphinx.ext.viewcode', + 'sphinx.ext.githubpages', + #'numpy_ext.numpydoc', + ] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'scikit-optimize' +copyright = '2017, The scikit-optimize contributors' +author = 'The scikit-optimize contributors' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.4' +# The full version, including alpha/beta/rc tags. +release = '0.4-dev' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +html_sidebars = { + '**': [ + 'about.html', + 'navigation.html', + 'relations.html', + 'searchbox.html', + 'donate.html', + ] +} + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +html_theme_options = { + 'logo': '../../../../media/logo.png', + 'github_user': 'scikit-optimize', + 'github_repo': 'scikit-optimize', + 'fixed_sidebar': True, + 'github_button': False, + 'github_banner': True, + } + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = 'scikit-optimizedoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'scikit-optimize.tex', 'scikit-optimize Documentation', + 'The scikit-optimize contributors', 'manual'), +] + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'scikit-optimize', 'scikit-optimize Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'scikit-optimize', 'scikit-optimize Documentation', + author, 'scikit-optimize', 'One line description of project.', + 'Miscellaneous'), +] diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..a7588d1 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,28 @@ +=========================================== +Welcome to scikit-optimize's documentation! +=========================================== + +Scikit-Optimize, or ``skopt``, is a simple and efficient library to +minimize (very) expensive and noisy black-box functions. It implements +several methods for sequential model-based optimization. ``skopt`` aims +to be accessible and easy to use in many contexts. + +The library is built on top of NumPy, SciPy and Scikit-Learn. + +We do not perform gradient-based optimization. For gradient-based +optimization algorithms look at +``scipy.optimize`` +`here `_. + +.. figure:: https://rawgit.com/scikit-optimize/scikit-optimize/master/media/bo-objective.png + :alt: Approximated objective + +Approximated objective function after 50 iterations of ``gp_minimize``. +Plot made using ``skopt.plots.plot_objective``. + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + intro + api/index diff --git a/docs/intro.rst b/docs/intro.rst new file mode 100644 index 0000000..1f04159 --- /dev/null +++ b/docs/intro.rst @@ -0,0 +1,21 @@ +========== +Quickstart +========== + +Find the minimum of the noisy function ``f(x)`` over the range ``-2 < x < 2`` +with ``skopt``:: + + import numpy as np + from skopt import gp_minimize + + def f(x): + return (np.sin(5 * x[0]) * (1 - np.tanh(x[0] ** 2)) * + np.random.randn() * 0.1) + + res = gp_minimize(f, [(-2.0, 2.0)]) + +For more read our `introduction to bayesian optimization`_ and the other +`examples`_. + +.. _introduction to bayesian optimization: https://scikit-optimize.github.io/notebooks/bayesian-optimization.html +.. _examples: https://github.com/scikit-optimize/scikit-optimize/tree/master/examples diff --git a/media/logo.png b/media/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2c66c002b0ff11892cd2d1e228d99c3559a1456e GIT binary patch literal 18280 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 z zIfyTPu#wN|jP$$5Z!EbwkUwtpXEFi9D^bc1x<;#ZhF(1cW6b2DjoOqEiEbNj)kNhd zo4mkqsz(rO>*gK&eW!fGfbKzf^;GviQx4JxudX-AfVczX zqRW|$TBFx;MEf2EuX>i>1?000%9+=dj92pid>{Zvnby(QE6>PRwAZYww@PeUMmsGQ z!Dp+mx-F$seRJ`bHj8ELLdu*Ud7=~Def9>9lwEUnQeL=-tt{)tc#f1UrlWCaUj-_U z8@?WGpZ7cM1s>~+_IEx8j^|qce8&cD2F0swX>+ab7I~VCmM$qefq(rr>|N@Lb{n_k zv%R1;cZs&DZWU5v!J`*|YZ8!8wW`X4)(h(zu`RQ7AfuhYvERNmom2NO03#UiDOh(m zbP$8}I)e!|mR3I(wOI`f_y~rm#P`_^h&!VJ`-_EGZy^$DN;fgc5eVLkEf&InT_(p@ zEZ~^~*m@LYA^1e7q|>E@8)Wfr!|c61|z+9f~}}P#+Ck$yP@L+qv&EPqAs7gz)+fP z>iGDb(FuD{(fK@Q+*vcWWsU*RY;7L-z21f*rhhdV^|+@G!hWc6(eXsaMa*SFrBu?1 zdMg8lo?;^;%MC)rJO(jDM>-?EEX@HFk@1;ex&DYpcLoqlzt>G?ST2^QE5mpa5IF6d zvVWP_k+o{?FYcEVri0RHwO5WJ=IC*(h-Q! z15;mAnO6#pP`GZJ&y9Sp@H!Cf8+A)vcfs@>`@jXW@qC&jx^Llc;Uoh)g=m+7;$i``|VE(Rp}4B2|B{ z&HO1lGX}lH;=}Xp6H~KW@Ap#sR&^_=!=x)>c!!0kb}HiF#%?>>L=;$G4q~+Jt@eiw PB)Fn_?NY`?{L}vnArR`C literal 0 HcmV?d00001 diff --git a/skopt/__init__.py b/skopt/__init__.py index 621faee..b7ede4f 100644 --- a/skopt/__init__.py +++ b/skopt/__init__.py @@ -1,49 +1,7 @@ """ -Scikit-Optimize, or `skopt`, is a simple and efficient library to +Scikit-Optimize, or ``skopt``, is a simple and efficient library to minimize (very) expensive and noisy black-box functions. It implements -several methods for sequential model-based optimization. `skopt` is reusable -in many contexts and accessible. - -[![Build Status](https://travis-ci.org/scikit-optimize/scikit-optimize.svg?branch=master)](https://travis-ci.org/scikit-optimize/scikit-optimize) - -## Install - -``` -pip install scikit-optimize -``` - -## Getting started - -Find the minimum of the noisy function `f(x)` over the range `-2 < x < 2` -with `skopt`: - -```python -import numpy as np -from skopt import gp_minimize - -def f(x): - return (np.sin(5 * x[0]) * (1 - np.tanh(x[0] ** 2)) * - np.random.randn() * 0.1) - -res = gp_minimize(f, [(-2.0, 2.0)]) -``` - -For more read our [introduction to bayesian optimization](https://scikit-optimize.github.io/notebooks/bayesian-optimization.html) -and the other [examples](https://github.com/scikit-optimize/scikit-optimize/tree/master/examples). - - -## Development - -The library is still experimental and under heavy development. - -The development version can be installed through: - - git clone https://github.com/scikit-optimize/scikit-optimize.git - cd scikit-optimize - pip install -r requirements.txt - python setup.py develop - -Run the tests by executing `pytest` in the top level directory. +several methods for sequential model-based optimization. """ from . import acquisition diff --git a/skopt/utils.py b/skopt/utils.py index fb19476..2cfe2f7 100644 --- a/skopt/utils.py +++ b/skopt/utils.py @@ -1,3 +1,4 @@ +"""Generally useful functions""" from copy import deepcopy import numpy as np From 32b9a0f9aa91240aed8371369c3338ef4c1b5525 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Wed, 12 Jul 2017 08:38:41 +0200 Subject: [PATCH 02/18] Enable numpydoc extension --- docs/api/utils.rst | 26 ++++++++++++++++++++++++++ docs/conf.py | 4 ++-- skopt/utils.py | 9 +++------ 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/docs/api/utils.rst b/docs/api/utils.rst index a649d4c..23a88b1 100644 --- a/docs/api/utils.rst +++ b/docs/api/utils.rst @@ -3,5 +3,31 @@ Utilities ========= +Overview +-------- + +.. currentmodule:: skopt + +.. autosummary:: + + utils.check_x_in_space + utils.cook_estimator + utils.create_result + utils.dimensions_aslist + utils.dump + utils.eval_callbacks + utils.expected_minimum + utils.has_gradients + utils.is_2Dlistlike + utils.is_listlike + utils.is_regressor + utils.load + utils.point_asdict + utils.point_aslist + + +Details +------- + .. automodule:: skopt.utils :members: diff --git a/docs/conf.py b/docs/conf.py index 91da377..8bcdc1b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -32,11 +32,11 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx.ext.autodoc', - #'sphinx.ext.autosummary', + 'sphinx.ext.autosummary', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', 'sphinx.ext.githubpages', - #'numpy_ext.numpydoc', + 'numpydoc', ] # Add any paths that contain templates here, relative to this directory. diff --git a/skopt/utils.py b/skopt/utils.py index 2cfe2f7..cadeb61 100644 --- a/skopt/utils.py +++ b/skopt/utils.py @@ -1,4 +1,6 @@ -"""Generally useful functions""" +""" +The :mod:`skopt.utils` module includes various utilities. +""" from copy import deepcopy import numpy as np @@ -20,11 +22,6 @@ from .space import check_dimension from .space import Categorical -__all__ = ( - "load", - "dump", -) - def create_result(Xi, yi, space=None, rng=None, specs=None, models=None): """ From 34453b67dbd7c1d40fdedb4479d695524316ad55 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Wed, 12 Jul 2017 08:46:27 +0200 Subject: [PATCH 03/18] Modify circlci setup --- build_tools/circle/execute.sh | 18 +-- build_tools/circle/install.sh | 2 +- build_tools/circle/make_doc.py | 349 ----------------------------------------- circle.yml | 1 - 4 files changed, 4 insertions(+), 366 deletions(-) delete mode 100644 build_tools/circle/make_doc.py diff --git a/build_tools/circle/execute.sh b/build_tools/circle/execute.sh index 742d225..7be5543 100644 --- a/build_tools/circle/execute.sh +++ b/build_tools/circle/execute.sh @@ -6,18 +6,6 @@ python --version python -c "import numpy; print('numpy %s' % numpy.__version__)" python -c "import scipy; print('scipy %s' % scipy.__version__)" -# Generating documentation -for nb in examples/*ipynb; do - jupyter nbconvert --ExecutePreprocessor.timeout=3600 --execute "$nb" --to markdown |& tee nb_to_md.txt - traceback=$(grep "Traceback (most recent call last):" nb_to_md.txt) - if [[ $traceback ]]; then - exit 1 - fi -done - -cd ~ -mkdir -p ${HOME}/doc/skopt/notebooks -cp ${SKOPT_HOME}/examples/*md ${HOME}/doc/skopt/notebooks -find ${SKOPT_HOME}/examples -name \*_files -exec cp -r {} ${HOME}/doc/skopt/notebooks \; -python ${SKOPT_HOME}/build_tools/circle/make_doc.py --overwrite --html --html-dir ./doc --template-dir ${SKOPT_HOME}/build_tools/circle/templates --notebook-dir ./doc/skopt/notebooks skopt -cp -r ./doc ${CIRCLE_ARTIFACTS} +cd ${SKOPT_HOME}/docs +make html +cp -r ./_build/html ${CIRCLE_ARTIFACTS} diff --git a/build_tools/circle/install.sh b/build_tools/circle/install.sh index b4d4a17..0f8b4b6 100644 --- a/build_tools/circle/install.sh +++ b/build_tools/circle/install.sh @@ -37,7 +37,7 @@ pip install -e. export SKOPT_HOME=$(pwd) conda install --yes jupyter -pip install pdoc==0.3.2 pygments +pip install sphinx numpydoc # importing matplotlib once builds the font caches. This avoids # having warnings in our example notebooks diff --git a/build_tools/circle/make_doc.py b/build_tools/circle/make_doc.py deleted file mode 100644 index 598a45b..0000000 --- a/build_tools/circle/make_doc.py +++ /dev/null @@ -1,349 +0,0 @@ -from __future__ import absolute_import, division, print_function -import argparse - -import codecs -import datetime -import imp -import os -import os.path as path -import subprocess -import sys -import tempfile -import glob - -import pdoc - -# `xrange` is `range` with Python3. -try: - xrange = xrange -except NameError: - xrange = range - -version_suffix = '%d.%d' % (sys.version_info[0], sys.version_info[1]) -default_http_dir = path.join(tempfile.gettempdir(), 'pdoc-%s' % version_suffix) - -parser = argparse.ArgumentParser( - description='Automatically generate API docs for Python modules.', - formatter_class=argparse.ArgumentDefaultsHelpFormatter) -aa = parser.add_argument -aa('module_name', type=str, nargs='?', - help='The Python module name. This may be an import path resolvable in ' - 'the current environment, or a file path to a Python module or ' - 'package.') -aa('ident_name', type=str, nargs='?', - help='When specified, only identifiers containing the name given ' - 'will be shown in the output. Search is case sensitive. ' - 'Has no effect when --http is set.') -aa('--version', action='store_true', - help='Print the version of pdoc and exit.') -aa('--html', action='store_true', - help='When set, the output will be HTML formatted.') -aa('--html-dir', type=str, default='.', - help='The directory to output HTML files to. This option is ignored when ' - 'outputting documentation as plain text.') -aa('--html-no-source', action='store_true', - help='When set, source code will not be viewable in the generated HTML. ' - 'This can speed up the time required to document large modules.') -aa('--overwrite', action='store_true', - help='Overwrites any existing HTML files instead of producing an error.') -aa('--all-submodules', action='store_true', - help='When set, every submodule will be included, regardless of whether ' - '__all__ is set and contains the submodule.') -aa('--external-links', action='store_true', - help='When set, identifiers to external modules are turned into links. ' - 'This is automatically set when using --http.') -aa('--template-dir', type=str, default=None, - help='Specify a directory containing Mako templates. ' - 'Alternatively, put your templates in $XDG_CONFIG_HOME/pdoc and ' - 'pdoc will automatically find them.') -aa('--notebook-dir', type=str, default=None, - help='Specify a directory containing Notebooks. ') -aa('--link-prefix', type=str, default='', - help='A prefix to use for every link in the generated documentation. ' - 'No link prefix results in all links being relative. ' - 'Has no effect when combined with --http.') -aa('--only-pypath', action='store_true', - help='When set, only modules in your PYTHONPATH will be documented.') -aa('--http', action='store_true', - help='When set, pdoc will run as an HTTP server providing documentation ' - 'of all installed modules. Only modules found in PYTHONPATH will be ' - 'listed.') -aa('--http-dir', type=str, default=default_http_dir, - help='The directory to cache HTML documentation when running as an HTTP ' - 'server.') -aa('--http-host', type=str, default='localhost', - help='The host on which to run the HTTP server.') -aa('--http-port', type=int, default=8080, - help='The port on which to run the HTTP server.') -aa('--http-html', action='store_true', - help='Internal use only. Do not set.') -args = parser.parse_args() - - -def quick_desc(imp, name, ispkg): - if not hasattr(imp, 'path'): - # See issue #7. - return '' - - if ispkg: - fp = path.join(imp.path, name, '__init__.py') - else: - fp = path.join(imp.path, '%s.py' % name) - if os.path.isfile(fp): - with codecs.open(fp, 'r', 'utf-8') as f: - quotes = None - doco = [] - for i, line in enumerate(f): - if i == 0: - if len(line) >= 3 and line[0:3] in ("'''", '"""'): - quotes = line[0:3] - line = line[3:] - else: - break - line = line.rstrip() - if line.endswith(quotes): - doco.append(line[0:-3]) - break - else: - doco.append(line) - desc = '\n'.join(doco) - if len(desc) > 200: - desc = desc[0:200] + '...' - return desc - return '' - - -def _eprint(*args, **kwargs): - kwargs['file'] = sys.stderr - print(*args, **kwargs) - - -def last_modified(fp): - try: - return datetime.datetime.fromtimestamp(os.stat(fp).st_mtime) - except: - return datetime.datetime.min - - -def module_file(m): - mbase = path.join(args.html_dir, *m.name.split('.')) - if m.is_package(): - return path.join(mbase, pdoc.html_package_name) - else: - return '%s%s' % (mbase, pdoc.html_module_suffix) - - -def quit_if_exists(m): - def check_file(f): - if os.access(f, os.R_OK): - _eprint('%s already exists. Delete it or run with --overwrite' % f) - sys.exit(1) - - if args.overwrite: - return - f = module_file(m) - check_file(f) - - # If this is a package, make sure the package directory doesn't exist - # either. - if m.is_package(): - check_file(path.dirname(f)) - - -def html_out(m, html=True, all_notebooks=[]): - f = module_file(m) - if not html: - f = module_file(m).replace(".html", ".md") - dirpath = path.dirname(f) - if not os.access(dirpath, os.R_OK): - os.makedirs(dirpath) - try: - with codecs.open(f, 'w+', 'utf-8') as w: - if not html: - out = m.text() - else: - out = m.html(external_links=args.external_links, - link_prefix=args.link_prefix, - http_server=args.http_html, - source=not args.html_no_source, - notebook=None, - all_notebooks=all_notebooks) - print(out, file=w) - except Exception: - try: - os.unlink(f) - except: - pass - raise - for submodule in m.submodules(): - html_out(submodule, html, all_notebooks=all_notebooks) - - -def html_out_notebook(m, notebook, all_notebooks=[]): - f = module_file(m) - f = f.rsplit(sep="/", maxsplit=1)[0] + "/notebooks/" + notebook.rsplit(sep="/", maxsplit=1)[-1][:-3] + ".html" - - dirpath = path.dirname(f) - if not os.access(dirpath, os.R_OK): - os.makedirs(dirpath) - try: - with codecs.open(f, 'w+', 'utf-8') as w: - out = m.html(external_links=args.external_links, - link_prefix=args.link_prefix, - http_server=args.http_html, - source=not args.html_no_source, - notebook=notebook, - all_notebooks=all_notebooks) - print(out, file=w) - except Exception: - try: - os.unlink(f) - except: - pass - raise - - - -def process_html_out(impath): - # This unfortunate kludge is the only reasonable way I could think of - # to support reloading of modules. It's just too difficult to get - # modules to reload in the same process. - - cmd = [sys.executable, - path.realpath(__file__), - '--html', - '--html-dir', args.html_dir, - '--http-html', - '--overwrite', - '--link-prefix', args.link_prefix] - if args.external_links: - cmd.append('--external-links') - if args.all_submodules: - cmd.append('--all-submodules') - if args.only_pypath: - cmd.append('--only-pypath') - if args.html_no_source: - cmd.append('--html-no-source') - if args.template_dir: - cmd.append('--template-dir') - cmd.append(args.template_dir) - cmd.append(impath) - - # Can we make a good faith attempt to support 2.6? - # YES WE CAN! - p = subprocess.Popen(cmd, stdin=subprocess.PIPE, - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - out = p.communicate()[0].strip().decode('utf-8') - if p.returncode > 0: - err = subprocess.CalledProcessError(p.returncode, cmd) - err.output = out - raise err - if len(out) > 0: - print(out) - - -if __name__ == '__main__': - if args.version: - print(pdoc.__version__) - sys.exit(0) - - # We close stdin because some modules, upon import, are not very polite - # and block on stdin. - try: - sys.stdin.close() - except: - pass - - if not args.http and args.module_name is None: - _eprint('No module name specified.') - sys.exit(1) - if args.template_dir is not None: - pdoc.tpl_lookup.directories.insert(0, args.template_dir) - - # If PYTHONPATH is set, let it override everything if we want it to. - pypath = os.getenv('PYTHONPATH') - if args.only_pypath and pypath is not None and len(pypath) > 0: - pdoc.import_path = pypath.split(path.pathsep) - - docfilter = None - if args.ident_name and len(args.ident_name.strip()) > 0: - search = args.ident_name.strip() - - def docfilter(o): - rname = o.refname - if rname.find(search) > -1 or search.find(o.name) > -1: - return True - if isinstance(o, pdoc.Class): - return search in o.doc or search in o.doc_init - return False - - # Try to do a real import first. I think it's better to prefer - # import paths over files. If a file is really necessary, then - # specify the absolute path, which is guaranteed not to be a - # Python import path. - try: - module = pdoc.import_module(args.module_name) - except Exception as e: - module = None - - # Get the module that we're documenting. Accommodate for import paths, - # files and directories. - if module is None: - print(module) - isdir = path.isdir(args.module_name) - isfile = path.isfile(args.module_name) - if isdir or isfile: - fp = path.realpath(args.module_name) - module_name = path.basename(fp) - if isdir: - fp = path.join(fp, '__init__.py') - else: - module_name, _ = path.splitext(module_name) - - # Use a special module name to avoid import conflicts. - # It is hidden from view via the `Module` class. - with open(fp) as f: - module = imp.load_source('__pdoc_file_module__', fp, f) - if isdir: - module.__path__ = [path.realpath(args.module_name)] - module.__pdoc_module_name = module_name - else: - module = pdoc.import_module(args.module_name) - module = pdoc.Module(module, docfilter=docfilter, - allsubmodules=args.all_submodules) - - # Plain text? - if not args.html and not args.all_submodules: - output = module.text() - try: - print(output) - except IOError as e: - # This seems to happen for long documentation. - # This is obviously a hack. What's the real cause? Dunno. - if e.errno == 32: - pass - else: - raise e - sys.exit(0) - - # Hook notebook generation - all_notebooks = [] - - if args.notebook_dir: - all_notebooks = [f for f in sorted(glob.glob("%s/*.md" % args.notebook_dir))] - - for notebook in all_notebooks: - html_out_notebook(module, notebook, all_notebooks=all_notebooks) - - # HTML output depends on whether the module being documented is a package - # or not. If not, then output is written to {MODULE_NAME}.html in - # `html-dir`. If it is a package, then a directory called {MODULE_NAME} - # is created, and output is written to {MODULE_NAME}/index.html. - # Submodules are written to {MODULE_NAME}/{MODULE_NAME}.m.html and - # subpackages are written to {MODULE_NAME}/{MODULE_NAME}/index.html. And - # so on... The same rules apply for `http_dir` when `pdoc` is run as an - # HTTP server. - if not args.http: - quit_if_exists(module) - html_out(module, args.html, all_notebooks=all_notebooks) - sys.exit(0) diff --git a/circle.yml b/circle.yml index 8b49775..6ef6812 100644 --- a/circle.yml +++ b/circle.yml @@ -8,7 +8,6 @@ test: override: - bash ./build_tools/circle/execute.sh: timeout: 3600 - - if grep -q "Traceback (most recent call last):" nb_to_md.txt; then false; else true; fi deployment: push: From beb783a371724e1a056b8abd07b5e74c6a5f293d Mon Sep 17 00:00:00 2001 From: Tim Head Date: Wed, 12 Jul 2017 08:52:30 +0200 Subject: [PATCH 04/18] Modify docs deploy setup --- build_tools/circle/deploy.sh | 2 +- build_tools/circle/execute.sh | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/build_tools/circle/deploy.sh b/build_tools/circle/deploy.sh index ba6dc24..630b86b 100644 --- a/build_tools/circle/deploy.sh +++ b/build_tools/circle/deploy.sh @@ -14,7 +14,7 @@ git clone -b master "git@github.com:scikit-optimize/scikit-optimize.github.io" d cd deploy git rm -r notebooks/* cd .. -cp -r ${HOME}/doc/skopt/* deploy +cp -r ${HOME}/doc/* deploy # Move into deployment directory cd deploy diff --git a/build_tools/circle/execute.sh b/build_tools/circle/execute.sh index 7be5543..903b22c 100644 --- a/build_tools/circle/execute.sh +++ b/build_tools/circle/execute.sh @@ -8,4 +8,6 @@ python -c "import scipy; print('scipy %s' % scipy.__version__)" cd ${SKOPT_HOME}/docs make html -cp -r ./_build/html ${CIRCLE_ARTIFACTS} +cp -r ./_build/html/* ${CIRCLE_ARTIFACTS} +mkdir ~/doc/ +cp -r ./_build/html/* ~/doc/ From 1168c6b14fa7241d7acb030a2b2bc9de5feb91b4 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Wed, 12 Jul 2017 09:43:46 +0200 Subject: [PATCH 05/18] Start work on reformatting doc strings --- {media => docs/_static}/logo.png | Bin docs/api/index.rst | 4 +- docs/api/minimize_functions.rst | 24 +++++++++-- docs/api/optimizer.rst | 11 +++++ docs/api/plots.rst | 23 ++++++++++ docs/conf.py | 2 +- skopt/optimizer/optimizer.py | 90 ++++++++++++++++++++------------------- 7 files changed, 105 insertions(+), 49 deletions(-) rename {media => docs/_static}/logo.png (100%) create mode 100644 docs/api/optimizer.rst create mode 100644 docs/api/plots.rst diff --git a/media/logo.png b/docs/_static/logo.png similarity index 100% rename from media/logo.png rename to docs/_static/logo.png diff --git a/docs/api/index.rst b/docs/api/index.rst index 220c154..c19d03e 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -2,9 +2,11 @@ API Reference ============= -Look at :ref:`minimize-functions`. Check :ref:`utility-functions` +Details on the complete API of scikit-optimize. .. toctree:: minimize_functions + optimizer + plots utils diff --git a/docs/api/minimize_functions.rst b/docs/api/minimize_functions.rst index fc1a380..77d3c17 100644 --- a/docs/api/minimize_functions.rst +++ b/docs/api/minimize_functions.rst @@ -3,9 +3,27 @@ Top level minimization functions ================================ -Easy to get started with these functions. They mirror the ``scipy.optimize`` -API. +These are easy to get started with. They mirror the ``scipy.optimize`` +API and provide a high level interface to various pre-configured +optimizers. -.. autofunction:: skopt.dummy_minimize +Overview +-------- + +.. currentmodule:: skopt + +.. autosummary:: + + dummy_minimize + forest_minimize + gbrt_minimize + gp_minimize + +Details +------- + +.. autofunction:: skopt.dummy_minimize +.. autofunction:: skopt.forest_minimize +.. autofunction:: skopt.gbrt_minimize .. autofunction:: skopt.gp_minimize diff --git a/docs/api/optimizer.rst b/docs/api/optimizer.rst new file mode 100644 index 0000000..70a50b4 --- /dev/null +++ b/docs/api/optimizer.rst @@ -0,0 +1,11 @@ +.. _optimizer: + +Optimizer +========= + +Use the ``Optimizer`` class directly when you want to control the optimization +loop. We refer to this as the ask-and-tell interface. This class is used +internally to implement the :ref:`minimize-functions`. + +.. autoclass:: skopt.Optimizer + :members: diff --git a/docs/api/plots.rst b/docs/api/plots.rst new file mode 100644 index 0000000..aa75397 --- /dev/null +++ b/docs/api/plots.rst @@ -0,0 +1,23 @@ +.. _plotting-functions: + +Plotting +======== + +Overview +-------- + +.. currentmodule:: skopt + +.. autosummary:: + + plots.partial_dependence + plots.plot_convergence + plots.plot_evaluations + plots.plot_objective + + +Details +------- + +.. automodule:: skopt.plots + :members: diff --git a/docs/conf.py b/docs/conf.py index 8bcdc1b..98a5746 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -106,7 +106,7 @@ # documentation. # html_theme_options = { - 'logo': '../../../../media/logo.png', + 'logo': 'logo.png', 'github_user': 'scikit-optimize', 'github_repo': 'scikit-optimize', 'fixed_sidebar': True, diff --git a/skopt/optimizer/optimizer.py b/skopt/optimizer/optimizer.py index a71872c..dd6aecb 100644 --- a/skopt/optimizer/optimizer.py +++ b/skopt/optimizer/optimizer.py @@ -37,7 +37,7 @@ class Optimizer(object): Parameters ---------- - * `dimensions` [list, shape=(n_dims,)]: + ``dimensions`` [list, shape=(n_dims,)]: List of search space dimensions. Each search dimension can be defined either as @@ -49,86 +49,86 @@ class Optimizer(object): - an instance of a `Dimension` object (`Real`, `Integer` or `Categorical`). - * `base_estimator` ["GP", "RF", "ET", "GBRT" or sklearn regressor, default="GP"]: - Should inherit from `sklearn.base.RegressorMixin`. - In addition the `predict` method, should have an optional `return_std` - argument, which returns `std(Y | x)`` along with `E[Y | x]`. + ``base_estimator`` ["GP", "RF", "ET", "GBRT" or sklearn regressor, default="GP"]: + Should inherit from ``sklearn.base.RegressorMixin``. + In addition the ``predict`` method, should have an optional ``return_std`` + argument, which returns ``std(Y | x)`` along with ``E[Y | x]``. If base_estimator is one of ["GP", "RF", "ET", "GBRT"], a default surrogate model of the corresponding type is used corresponding to what is used in the minimize functions. - * `n_random_starts` [int, default=10]: - DEPRECATED, use `n_initial_points` instead. + ``n_random_starts`` [int, default=10]: + DEPRECATED, use ``n_initial_points`` instead. - * `n_initial_points` [int, default=10]: - Number of evaluations of `func` with initialization points - before approximating it with `base_estimator`. Points provided as - `x0` count as initialization points. If len(x0) < n_initial_points + ``n_initial_points`` [int, default=10]: + Number of evaluations of ``func`` with initialization points + before approximating it with ``base_estimator``. Points provided as + ``x0`` count as initialization points. If len(x0) < n_initial_points additional points are sampled at random. - * `acq_func` [string, default=`"EI"`]: + ``acq_func`` [string, default=``"EI"``]: Function to minimize over the posterior distribution. Can be either - - `"LCB"` for lower confidence bound. - - `"EI"` for negative expected improvement. - - `"PI"` for negative probability of improvement. - - `"gp_hedge"` Probabilistically choose one of the above three + - ``"LCB"`` for lower confidence bound. + - ``"EI"`` for negative expected improvement. + - ``"PI"`` for negative probability of improvement. + - ``"gp_hedge"`` Probabilistically choose one of the above three acquisition functions at every iteration. - - The gains `g_i` are initialized to zero. + - The gains ``g_i`` are initialized to zero. - At every iteration, - Each acquisition function is optimised independently to - propose an candidate point `X_i`. - - Out of all these candidate points, the next point `X_best` is + propose an candidate point ``X_i``. + - Out of all these candidate points, the next point ``X_best`` is chosen by $softmax(\eta g_i)$ - - After fitting the surrogate model with `(X_best, y_best)`, + - After fitting the surrogate model with ``(X_best, y_best)``, the gains are updated such that $g_i -= \mu(X_i)$ - - `"EIps" for negated expected improvement per second to take into + - ``"EIps"`` for negated expected improvement per second to take into account the function compute time. Then, the objective function is assumed to return two values, the first being the objective value and the second being the time taken in seconds. - - `"PIps"` for negated probability of improvement per second. The + - ``"PIps"`` for negated probability of improvement per second. The return type of the objective function is assumed to be similar to - that of `"EIps + that of ``"EIps"``. - * `acq_optimizer` [string, `"sampling"` or `"lbfgs"`, default=`"auto"`]: + ``acq_optimizer`` [string, ``"sampling"`` or ``"lbfgs"``, default=``"auto"``]: Method to minimize the acquistion function. The fit model - is updated with the optimal value obtained by optimizing `acq_func` - with `acq_optimizer`. + is updated with the optimal value obtained by optimizing ``acq_func`` + with ``acq_optimizer``. - - If set to `"auto"`, then `acq_optimizer` is configured on the + - If set to ``"auto"``, then ``acq_optimizer`` is configured on the basis of the base_estimator and the space searched over. If the space is Categorical or if the estimator provided based on - tree-models then this is set to be "sampling"`. - - If set to `"sampling"`, then `acq_func` is optimized by computing - `acq_func` at `n_points` randomly sampled points. - - If set to `"lbfgs"`, then `acq_func` is optimized by - - Sampling `n_restarts_optimizer` points randomly. - - `"lbfgs"` is run for 20 iterations with these points as initial + tree-models then this is set to be ``"sampling"``. + - If set to ``"sampling"``, then ``acq_func`` is optimized by computing + ``acq_func`` at ``n_points`` randomly sampled points. + - If set to ``"lbfgs"``, then ``acq_func`` is optimized by + - Sampling ``n_restarts_optimizer`` points randomly. + - ``"lbfgs"`` is run for 20 iterations with these points as initial points to find local minima. - The optimal of these local minima is used to update the prior. - * `random_state` [int, RandomState instance, or None (default)]: + ``random_state`` [int, RandomState instance, or None (default)]: Set random state to something other than None for reproducible results. - * `acq_func_kwargs` [dict]: + ``acq_func_kwargs`` [dict]: Additional arguments to be passed to the acquistion function. - * `acq_optimizer_kwargs` [dict]: + ``acq_optimizer_kwargs`` [dict]: Additional arguments to be passed to the acquistion optimizer. Attributes ---------- - * `Xi` [list]: + * ``Xi`` [list]: Points at which objective has been evaluated. - * `yi` [scalar]: - Values of objective at corresponding points in `Xi`. - * `models` [list]: + * ``yi`` [scalar]: + Values of objective at corresponding points in ``Xi``. + * ``models`` [list]: Regression models used to fit observations and compute acquisition function. - * `space` - An instance of `skopt.space.Space`. Stores parameter search space used + * ``space`` + An instance of ``skopt.space.Space``. Stores parameter search space used to sample points, bounds, and type of parameters. """ @@ -269,6 +269,8 @@ def copy(self, random_state=None): def ask(self, n_points=None, strategy="cl_min"): """Query point or multiple points at which objective should be evaluated. + Parameters + ---------- * `n_points` [int or None, default=None]: Number of points returned by the ask method. If the value is None, a single point to evaluate is returned. @@ -369,11 +371,11 @@ def _ask(self): def tell(self, x, y, fit=True): """Record an observation (or several) of the objective function. - Provide values of the objective function at points suggested by `ask()` + Provide values of the objective function at points suggested by ``ask()`` or other points. By default a new model will be fit to all observations. The new model is used to suggest the next point at which to evaluate the objective. This point can be retrieved by calling - `ask()`. + ``ask()``. To add observations without fitting a new model set `fit` to False. From f7339649ee80a7756de2804349d64bf885a42a53 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Wed, 12 Jul 2017 19:45:47 +0200 Subject: [PATCH 06/18] Update docstrings for Optimizer --- docs/api/index.rst | 1 + docs/api/minimize_functions.rst | 4 +- docs/api/optimizer.rst | 5 +- docs/api/plots.rst | 4 +- docs/api/space.rst | 30 ++++++++++ docs/api/utils.rst | 4 +- skopt/optimizer/optimizer.py | 119 ++++++++++++++++++++-------------------- 7 files changed, 100 insertions(+), 67 deletions(-) create mode 100644 docs/api/space.rst diff --git a/docs/api/index.rst b/docs/api/index.rst index c19d03e..d37d796 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -5,6 +5,7 @@ API Reference Details on the complete API of scikit-optimize. .. toctree:: + :maxdepth: 1 minimize_functions optimizer diff --git a/docs/api/minimize_functions.rst b/docs/api/minimize_functions.rst index 77d3c17..5cb2464 100644 --- a/docs/api/minimize_functions.rst +++ b/docs/api/minimize_functions.rst @@ -1,7 +1,7 @@ .. _minimize-functions: -Top level minimization functions -================================ +``skopt``'s top level minimization functions +============================================ These are easy to get started with. They mirror the ``scipy.optimize`` API and provide a high level interface to various pre-configured diff --git a/docs/api/optimizer.rst b/docs/api/optimizer.rst index 70a50b4..eefe0a0 100644 --- a/docs/api/optimizer.rst +++ b/docs/api/optimizer.rst @@ -1,11 +1,12 @@ .. _optimizer: -Optimizer -========= +``skopt.Optimizer``, ask-and-tell interface +=========================================== Use the ``Optimizer`` class directly when you want to control the optimization loop. We refer to this as the ask-and-tell interface. This class is used internally to implement the :ref:`minimize-functions`. +.. currentmodule:: skopt.Optimizer .. autoclass:: skopt.Optimizer :members: diff --git a/docs/api/plots.rst b/docs/api/plots.rst index aa75397..c98a8e0 100644 --- a/docs/api/plots.rst +++ b/docs/api/plots.rst @@ -1,7 +1,7 @@ .. _plotting-functions: -Plotting -======== +``skopt.plots``, plotting tools +=============================== Overview -------- diff --git a/docs/api/space.rst b/docs/api/space.rst new file mode 100644 index 0000000..2d74b40 --- /dev/null +++ b/docs/api/space.rst @@ -0,0 +1,30 @@ +.. _optimization-space: + +``skopt.space``, define the optimization space +============================================== + +Overview +-------- + +.. currentmodule:: skopt + +.. autosummary:: + + space.check_dimension + space.Dimension + space.Categorical + space.Integer + space.Real + space.Pipeline + space.Normalize + space.Identity + space.Log10 + space.Pipeline + space.Space + + +Details +------- + +.. automodule:: skopt.utils + :members: diff --git a/docs/api/utils.rst b/docs/api/utils.rst index 23a88b1..3722b7d 100644 --- a/docs/api/utils.rst +++ b/docs/api/utils.rst @@ -1,7 +1,7 @@ .. _utility-functions: -Utilities -========= +``skopt.utils``, utility functions +================================== Overview -------- diff --git a/skopt/optimizer/optimizer.py b/skopt/optimizer/optimizer.py index dd6aecb..ad496ff 100644 --- a/skopt/optimizer/optimizer.py +++ b/skopt/optimizer/optimizer.py @@ -28,108 +28,109 @@ class Optimizer(object): """Run bayesian optimisation loop. - An `Optimizer` represents the steps of a bayesian optimisation loop. To + An ``Optimizer`` represents the steps of a bayesian optimisation loop. To use it you need to provide your own loop mechanism. The various - optimisers provided by `skopt` use this class under the hood. + optimisers provided by scikit-optimize use this class under the hood. Use this class directly if you want to control the iterations of your bayesian optimisation loop. Parameters ---------- - ``dimensions`` [list, shape=(n_dims,)]: + dimensions : list, shape=[n_dims] List of search space dimensions. Each search dimension can be defined either as - a `(upper_bound, lower_bound)` tuple (for `Real` or `Integer` dimensions), - - a `(upper_bound, lower_bound, "prior")` tuple (for `Real` + - a `(upper_bound, lower_bound, 'prior')` tuple (for `Real` dimensions), - as a list of categories (for `Categorical` dimensions), or - an instance of a `Dimension` object (`Real`, `Integer` or `Categorical`). - ``base_estimator`` ["GP", "RF", "ET", "GBRT" or sklearn regressor, default="GP"]: - Should inherit from ``sklearn.base.RegressorMixin``. - In addition the ``predict`` method, should have an optional ``return_std`` - argument, which returns ``std(Y | x)`` along with ``E[Y | x]``. - If base_estimator is one of ["GP", "RF", "ET", "GBRT"], a default + base_estimator : {'GP', 'RF', 'ET', 'GBRT', sklearn regressor}, optional (default='GP') + If not a string then should inherit from + ``sklearn.base.RegressorMixin``. In addition the ``predict`` method, + should have an optional ``return_std`` argument, which returns + ``std(Y | x)`` along with ``E[Y | x]``. + If base_estimator is one of ['GP', 'RF', 'ET', 'GBRT'], a default surrogate model of the corresponding type is used corresponding to what is used in the minimize functions. - ``n_random_starts`` [int, default=10]: + n_random_starts : int, optional (default=10) DEPRECATED, use ``n_initial_points`` instead. - ``n_initial_points`` [int, default=10]: + n_initial_points : int, optional (default=10) Number of evaluations of ``func`` with initialization points before approximating it with ``base_estimator``. Points provided as ``x0`` count as initialization points. If len(x0) < n_initial_points additional points are sampled at random. - ``acq_func`` [string, default=``"EI"``]: + acq_func : string, optional (default='gp_hedge') Function to minimize over the posterior distribution. Can be either - - ``"LCB"`` for lower confidence bound. - - ``"EI"`` for negative expected improvement. - - ``"PI"`` for negative probability of improvement. - - ``"gp_hedge"`` Probabilistically choose one of the above three + - 'LCB' for lower confidence bound. + - 'EI' for negative expected improvement. + - 'PI' for negative probability of improvement. + - 'gp_hedge' Probabilistically choose one of the above three acquisition functions at every iteration. - The gains ``g_i`` are initialized to zero. - At every iteration, - Each acquisition function is optimised independently to propose an candidate point ``X_i``. - - Out of all these candidate points, the next point ``X_best`` is - chosen by $softmax(\eta g_i)$ + - Out of all these candidate points, the next point ``X_best`` + is chosen by ``softmax(\eta g_i)`` - After fitting the surrogate model with ``(X_best, y_best)``, - the gains are updated such that $g_i -= \mu(X_i)$ - - ``"EIps"`` for negated expected improvement per second to take into + the gains are updated such that ``g_i -= \mu(X_i)`` + - 'EIps' for negated expected improvement per second to take into account the function compute time. Then, the objective function is assumed to return two values, the first being the objective value and the second being the time taken in seconds. - - ``"PIps"`` for negated probability of improvement per second. The + - 'PIps' for negated probability of improvement per second. The return type of the objective function is assumed to be similar to - that of ``"EIps"``. + that of 'EIps'. - ``acq_optimizer`` [string, ``"sampling"`` or ``"lbfgs"``, default=``"auto"``]: + acq_optimizer : {'sampling', 'lbfgs'}, optional (default='auto') Method to minimize the acquistion function. The fit model is updated with the optimal value obtained by optimizing ``acq_func`` with ``acq_optimizer``. - - If set to ``"auto"``, then ``acq_optimizer`` is configured on the + - If set to 'auto', then ``acq_optimizer`` is configured on the basis of the base_estimator and the space searched over. If the space is Categorical or if the estimator provided based on - tree-models then this is set to be ``"sampling"``. - - If set to ``"sampling"``, then ``acq_func`` is optimized by computing + tree-models then this is set to be 'sampling'. + - If set to 'sampling', then ``acq_func`` is optimized by computing ``acq_func`` at ``n_points`` randomly sampled points. - - If set to ``"lbfgs"``, then ``acq_func`` is optimized by + - If set to 'lbfgs', then ``acq_func`` is optimized by - Sampling ``n_restarts_optimizer`` points randomly. - - ``"lbfgs"`` is run for 20 iterations with these points as initial + - 'lbfgs' is run for 20 iterations with these points as initial points to find local minima. - The optimal of these local minima is used to update the prior. - ``random_state`` [int, RandomState instance, or None (default)]: + random_state : int, RandomState instance or None, optional (default=None) Set random state to something other than None for reproducible results. - ``acq_func_kwargs`` [dict]: + acq_func_kwargs : dict Additional arguments to be passed to the acquistion function. - ``acq_optimizer_kwargs`` [dict]: + acq_optimizer_kwargs : dict Additional arguments to be passed to the acquistion optimizer. Attributes ---------- - * ``Xi`` [list]: + Xi : list Points at which objective has been evaluated. - * ``yi`` [scalar]: + yi : scalar Values of objective at corresponding points in ``Xi``. - * ``models`` [list]: + models : list Regression models used to fit observations and compute acquisition function. - * ``space`` - An instance of ``skopt.space.Space``. Stores parameter search space used - to sample points, bounds, and type of parameters. + space : skopt.space.Space + An instance of ``skopt.space.Space``. Stores parameter search space + used to sample points, bounds, and type of parameters. """ def __init__(self, dimensions, base_estimator="gp", @@ -243,7 +244,7 @@ def copy(self, random_state=None): Parameters ---------- - * `random_state` [int, RandomState instance, or None (default)]: + random_state : int, RandomState instance or None, optional (default=None) Set the random state of the copy. """ @@ -271,7 +272,7 @@ def ask(self, n_points=None, strategy="cl_min"): Parameters ---------- - * `n_points` [int or None, default=None]: + n_points : int or None, optional (default=None) Number of points returned by the ask method. If the value is None, a single point to evaluate is returned. Otherwise a list of points to evaluate is returned of size @@ -279,14 +280,14 @@ def ask(self, n_points=None, strategy="cl_min"): parallel, and thus obtain more objective function evaluations per unit of time. - * `strategy` [string, default=`"cl_min"`]: - Method to use to sample multiple points (see also `n_points` - description). This parameter is ignored if n_points = None. - Supported options are `"cl_min"`, `"cl_mean"` or `"cl_max"`. + strategy : string, optional (default='cl_min') + Method to use to sample multiple points (see also ``n_points`` + description). This parameter is ignored if ``n_points=None``. + Supported options are 'cl_min', 'cl_mean' or 'cl_max'. - - If set to `"cl_min"`, then constant liar strtategy is used + - If set to 'cl_min', then constant liar strtategy is used with lie objective value being minimum of observed objective - values. `"cl_mean"` and `"cl_max"` means mean and max of values + values. 'cl_mean' and 'cl_max' means mean and max of values respectively. For details on this strategy see: https://hal.archives-ouvertes.fr/hal-00732512/document @@ -296,7 +297,7 @@ def ask(self, n_points=None, strategy="cl_min"): optimizer with some fake objective (lie), the next point is asked from copy, it is also told to the copy with fake objective and so on. The type of lie defines different - flavours of `cl_x` strategies. + flavours of ``cl_x`` strategies. """ if n_points is None: @@ -344,8 +345,8 @@ def ask(self, n_points=None, strategy="cl_min"): def _ask(self): """Suggest next point at which to evaluate the objective. - Return a random point while not at least `n_initial_points` - observations have been `tell`ed, after that `base_estimator` is used + Return a random point while not at least ``n_initial_points`` + observations have been `tell`ed, after that ``base_estimator`` is used to determine the next point. """ if self._n_initial_points > 0 or self.base_estimator_ is None: @@ -371,11 +372,11 @@ def _ask(self): def tell(self, x, y, fit=True): """Record an observation (or several) of the objective function. - Provide values of the objective function at points suggested by ``ask()`` - or other points. By default a new model will be fit to all - observations. The new model is used to suggest the next point at - which to evaluate the objective. This point can be retrieved by calling - ``ask()``. + Provide values of the objective function at points suggested by + ``ask()`` or other points. By default a new model will be + fit to all observations. The new model is used to suggest the next + point at which to evaluate the objective. This point can be retrieved + by calling ``ask()``. To add observations without fitting a new model set `fit` to False. @@ -384,16 +385,16 @@ def tell(self, x, y, fit=True): Parameters ---------- - * `x` [list or list-of-lists]: + x : list or list-of-lists Point at which objective was evaluated. - * `y` [scalar or list]: + y : scalar or list Value of objective at `x`. - * `fit` [bool, default=True] + fit : bool, optional (default=True) Fit a model to observed evaluations of the objective. A model will - only be fitted after `n_initial_points` points have been told to - the optimizer irrespective of the value of `fit`. + only be fitted after ``n_initial_points`` points have been told to + the optimizer irrespective of the value of ``fit``. """ check_x_in_space(x, self.space) @@ -514,7 +515,7 @@ def tell(self, x, y, fit=True): models=self.models) def run(self, func, n_iter=1): - """Execute ask() + tell() `n_iter` times""" + """Execute ask() + tell() ``n_iter`` times""" for _ in range(n_iter): x = self.ask() self.tell(x, func(x)) From b2926a19c6ada940ff4568ff817a082c466594a5 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Wed, 12 Jul 2017 21:33:34 +0200 Subject: [PATCH 07/18] Docs docs docs --- docs/api/index.rst | 2 ++ docs/api/plots.rst | 10 +++++----- docs/api/space.rst | 21 ++++++++------------- docs/api/utils.rst | 11 ++++------- docs/conf.py | 2 +- 5 files changed, 20 insertions(+), 26 deletions(-) diff --git a/docs/api/index.rst b/docs/api/index.rst index d37d796..1a21f1f 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -9,5 +9,7 @@ Details on the complete API of scikit-optimize. minimize_functions optimizer + bayessearchcv plots + space utils diff --git a/docs/api/plots.rst b/docs/api/plots.rst index c98a8e0..8bf4c3a 100644 --- a/docs/api/plots.rst +++ b/docs/api/plots.rst @@ -6,14 +6,14 @@ Overview -------- -.. currentmodule:: skopt +.. currentmodule:: skopt.plots .. autosummary:: - plots.partial_dependence - plots.plot_convergence - plots.plot_evaluations - plots.plot_objective + partial_dependence + plot_convergence + plot_evaluations + plot_objective Details diff --git a/docs/api/space.rst b/docs/api/space.rst index 2d74b40..c7f4ba6 100644 --- a/docs/api/space.rst +++ b/docs/api/space.rst @@ -6,25 +6,20 @@ Overview -------- -.. currentmodule:: skopt +.. currentmodule:: skopt.space .. autosummary:: - space.check_dimension - space.Dimension - space.Categorical - space.Integer - space.Real - space.Pipeline - space.Normalize - space.Identity - space.Log10 - space.Pipeline - space.Space + check_dimension + Dimension + Categorical + Integer + Real + Space Details ------- -.. automodule:: skopt.utils +.. automodule:: skopt.space :members: diff --git a/docs/api/utils.rst b/docs/api/utils.rst index 3722b7d..1bbdf71 100644 --- a/docs/api/utils.rst +++ b/docs/api/utils.rst @@ -6,21 +6,18 @@ Overview -------- +This is a list of public utility functions. Other functions in this module +are meant for internal use. + .. currentmodule:: skopt .. autosummary:: utils.check_x_in_space utils.cook_estimator - utils.create_result utils.dimensions_aslist - utils.dump - utils.eval_callbacks utils.expected_minimum - utils.has_gradients - utils.is_2Dlistlike - utils.is_listlike - utils.is_regressor + utils.dump utils.load utils.point_asdict utils.point_aslist diff --git a/docs/conf.py b/docs/conf.py index 98a5746..920b959 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -109,7 +109,7 @@ 'logo': 'logo.png', 'github_user': 'scikit-optimize', 'github_repo': 'scikit-optimize', - 'fixed_sidebar': True, + 'fixed_sidebar': False, 'github_button': False, 'github_banner': True, } From c02e76588959d9519107ee3344b1874e6f5682e7 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Wed, 12 Jul 2017 21:33:59 +0200 Subject: [PATCH 08/18] Restructure the API of skopt.space --- skopt/space/__init__.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/skopt/space/__init__.py b/skopt/space/__init__.py index c48007e..8abd828 100644 --- a/skopt/space/__init__.py +++ b/skopt/space/__init__.py @@ -1,5 +1,10 @@ """ -Utilities to define a search space. +Define the search space of the optimization problem. """ -from .space import * +from .space import Categorical +from .space import Dimension +from .space import Integer +from .space import Real +from .space import Space +from .space import check_dimension From 28b0a559a9848a5225b116a067fc412a423614dc Mon Sep 17 00:00:00 2001 From: Tim Head Date: Wed, 12 Jul 2017 22:09:10 +0200 Subject: [PATCH 09/18] Reformat space docstrings --- skopt/space/space.py | 119 +++++++++++++++++++++++++-------------------------- 1 file changed, 59 insertions(+), 60 deletions(-) diff --git a/skopt/space/space.py b/skopt/space/space.py index 6d04276..f5b51bb 100644 --- a/skopt/space/space.py +++ b/skopt/space/space.py @@ -99,10 +99,10 @@ def rvs(self, n_samples=1, random_state=None): Parameters ---------- - * `n_samples` [int or None]: + n_samples : int or None, optional (default=1) The number of samples to be drawn. - * `random_state` [int, RandomState instance, or None (default)]: + random_state : int, RandomState instance or None, optional (default=None) Set random state to something other than None for reproducible results. """ @@ -150,25 +150,25 @@ def __init__(self, low, high, prior="uniform", transform=None): Parameters ---------- - * `low` [float]: + low : float Lower bound (inclusive). - * `high` [float]: + high : float Upper bound (inclusive). - * `prior` ["uniform" or "log-uniform", default="uniform"]: + prior : 'uniform' or 'log-uniform', optional, (default='uniform') Distribution to use when sampling random points for this dimension. - - If `"uniform"`, points are sampled uniformly between the lower + - If ``uniform``, points are sampled uniformly between the lower and upper bounds. - - If `"log-uniform"`, points are sampled uniformly between - `log10(lower)` and `log10(upper)`.` + - If ``log-uniform``, points are sampled uniformly between + ``log10(lower)`` and ``log10(upper)``. - * `transform` ["identity", "normalize", optional]: + transform : 'identity' or 'normalize', optional (default='identity') The following transformations are supported. - - "identity", (default) the transformed space is the same as the + - 'identity', the transformed space is the same as the original space. - - "normalize", the transformed space is scaled to be between + - 'normalize', the transformed space is scaled to be between 0 and 1. """ self.low = low @@ -244,14 +244,14 @@ def transformed_bounds(self): return np.log10(self.low), np.log10(self.high) def distance(self, a, b): - """Compute distance between point `a` and `b`. + """Compute distance between point ``a`` and ``b``. Parameters ---------- - * `a` [float] + a : float First point. - * `b` [float] + b : float Second point. """ if not (a in self and b in self): @@ -266,16 +266,16 @@ def __init__(self, low, high, transform=None): Parameters ---------- - * `low` [int]: + low : int Lower bound (inclusive). - * `high` [int]: + high : int Upper bound (inclusive). - * `transform` ["identity", "normalize", optional]: + transform : 'identity' or 'normalize', optional (default='identity') The following transformations are supported. - - "identity", (default) the transformed space is the same as the + - "identity", the transformed space is the same as the original space. - "normalize", the transformed space is scaled to be between 0 and 1. @@ -329,14 +329,14 @@ def transformed_bounds(self): return (self.low, self.high) def distance(self, a, b): - """Compute distance between point `a` and `b`. + """Compute distance between point ``a`` and ``b``. Parameters ---------- - * `a` [int] + a : float First point. - * `b` [int] + b : float Second point. """ if not (a in self and b in self): @@ -351,17 +351,17 @@ def __init__(self, categories, prior=None, transform=None): Parameters ---------- - * `categories` [list, shape=(n_categories,)]: + categories : list, shape=[n_categories] Sequence of possible categories. - * `prior` [list, shape=(categories,), default=None]: + prior : list, shape=[categories], optional (default=None) Prior probabilities for each category. By default all categories are equally likely. - * `transform` ["onehot", "identity", default="onehot"] : - - "identity", the transformed space is the same as the original + transform : 'onehot' or 'identity', optional (default='onehot') + - 'identity', the transformed space is the same as the original space. - - "onehot", the transformed space is a one-hot encoded + - 'onehot', the transformed space is a one-hot encoded representation of the original space. """ self.categories = categories @@ -440,17 +440,17 @@ def transformed_bounds(self): return [(0.0, 1.0) for i in range(self.transformed_size)] def distance(self, a, b): - """Compute distance between category `a` and `b`. + """Compute distance between category ``a`` and ``b``. As categories have no order the distance between two points is one if a != b and zero otherwise. Parameters ---------- - * `a` [category] + a : category First category. - * `b` [category] + b : category Second category. """ if not (a in self and b in self): @@ -460,28 +460,27 @@ def distance(self, a, b): class Space(object): - """Search space.""" + """Search space - def __init__(self, dimensions): - """Initialize a search space from given specifications. + Parameters + ---------- + dimensions : list, shape=[n_dims] + List of search space dimensions. + Each search dimension can be defined either as - Parameters - ---------- - * `dimensions` [list, shape=(n_dims,)]: - List of search space dimensions. - Each search dimension can be defined either as - - - a `(lower_bound, upper_bound)` tuple (for `Real` or `Integer` - dimensions), - - a `(lower_bound, upper_bound, "prior")` tuple (for `Real` - dimensions), - - as a list of categories (for `Categorical` dimensions), or - - an instance of a `Dimension` object (`Real`, `Integer` or - `Categorical`). - - NOTE: The upper and lower bounds are inclusive for `Integer` - dimensions. - """ + - a ``(lower_bound, upper_bound)`` tuple (for ``Real`` or ``Integer`` + dimensions), + - a ``(lower_bound, upper_bound, 'prior')`` tuple (for ``Real`` + dimensions), + - as a list of categories (for ``Categorical`` dimensions), or + - an instance of a ``Dimension`` object (``Real``, ``Integer`` or + ``Categorical``). + + NOTE: The upper and lower bounds are inclusive for ``Integer`` + dimensions. + """ + + def __init__(self, dimensions): self.dimensions = [check_dimension(dim) for dim in dimensions] def __eq__(self, other): @@ -508,20 +507,20 @@ def rvs(self, n_samples=1, random_state=None): """Draw random samples. The samples are in the original space. They need to be transformed - before being passed to a model or minimizer by `space.transform()`. + before being passed to a model or minimizer by ``space.transform()``. Parameters ---------- - * `n_samples` [int, default=1]: + n_samples : int, optional (default=1) Number of samples to be drawn from the space. - * `random_state` [int, RandomState instance, or None (default)]: + random_state : int, RandomState instance or None, optional (default=None) Set random state to something other than None for reproducible results. Returns ------- - * `points`: [list of lists, shape=(n_points, n_dims)] + points : list of lists, shape=[n_points, n_dims] Points sampled from the space. """ rng = check_random_state(random_state) @@ -555,12 +554,12 @@ def transform(self, X): Parameters ---------- - * `X` [list of lists, shape=(n_samples, n_dims)]: + X : list of lists, shape=[n_samples, n_dims] The samples to transform. Returns ------- - * `Xt` [array of floats, shape=(n_samples, transformed_n_dims)] + Xt : array of floats, shape=[n_samples, transformed_n_dims] The transformed samples. """ # Pack by dimension @@ -587,12 +586,12 @@ def inverse_transform(self, Xt): Parameters ---------- - * `Xt` [array of floats, shape=(n_samples, transformed_n_dims)]: + Xt : array of floats, shape=[n_samples, transformed_n_dims] The samples to inverse transform. Returns ------- - * `X` [list of lists, shape=(n_samples, n_dims)] + X : list of lists, shape=[n_samples, n_dims] The original samples. """ # Inverse transform @@ -647,7 +646,7 @@ def bounds(self): return b def __contains__(self, point): - """Check that `point` is within the bounds of the space.""" + """Check that ``point`` is within the bounds of the space.""" for component, dim in zip(point, self.dimensions): if component not in dim: return False @@ -675,10 +674,10 @@ def distance(self, point_a, point_b): Parameters ---------- - * `a` [array] + a : array First point. - * `b` [array] + `b : array Second point. """ distance = 0. From d51c2f5e3098b3347ccf192707071274f35034b1 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Thu, 13 Jul 2017 07:47:34 +0200 Subject: [PATCH 10/18] Add plotting and acquisition functions to docs --- docs/api/acquisition.rst | 23 +++++++++++ docs/api/bayessearchcv.rst | 10 +++++ docs/api/index.rst | 1 + skopt/acquisition.py | 56 +++++++++++++++------------ skopt/plots.py | 95 +++++++++++++++++++++++----------------------- 5 files changed, 113 insertions(+), 72 deletions(-) create mode 100644 docs/api/acquisition.rst create mode 100644 docs/api/bayessearchcv.rst diff --git a/docs/api/acquisition.rst b/docs/api/acquisition.rst new file mode 100644 index 0000000..c2888f1 --- /dev/null +++ b/docs/api/acquisition.rst @@ -0,0 +1,23 @@ +.. _acquisition-functions: + +``skopt.acquisition``, acquisition functions +============================================ + +Overview +-------- + +.. currentmodule:: skopt.acquisition + +.. autosummary:: + + gaussian_acquisition_1D + gaussian_ei + gaussian_lcb + gaussian_pi + + +Details +------- + +.. automodule:: skopt.acquisition + :members: diff --git a/docs/api/bayessearchcv.rst b/docs/api/bayessearchcv.rst new file mode 100644 index 0000000..b5d42af --- /dev/null +++ b/docs/api/bayessearchcv.rst @@ -0,0 +1,10 @@ +.. _bayessearchcv: + +``skopt.BayesSearchCV``, GridSearchCV compatible estimator +========================================================== + +Use ``BayesSearchCV`` as a replacement for scikit-learn's GridSearchCV. + +.. currentmodule:: skopt.BayesSearchCV +.. autoclass:: skopt.BayesSearchCV + :members: diff --git a/docs/api/index.rst b/docs/api/index.rst index 1a21f1f..1211c47 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -10,6 +10,7 @@ Details on the complete API of scikit-optimize. minimize_functions optimizer bayessearchcv + acquisition plots space utils diff --git a/skopt/acquisition.py b/skopt/acquisition.py index 8693fea..5fb5bd4 100644 --- a/skopt/acquisition.py +++ b/skopt/acquisition.py @@ -9,7 +9,7 @@ def gaussian_acquisition_1D(X, model, y_opt=None, acq_func="LCB", """ A wrapper around the acquisition function that is called by fmin_l_bfgs_b. - This is because lbfgs allows only 1-D input. + This is because lbfgs accepts only 1-D input. """ return _gaussian_acquisition(np.expand_dims(X, axis=0), model, y_opt, acq_func=acq_func, @@ -96,16 +96,16 @@ def gaussian_lcb(X, model, kappa=1.96, return_grad=False): Parameters ---------- - * `X` [array-like, shape=(n_samples, n_features)]: + X : array-like, shape=[n_samples, n_features] Values where the acquisition function should be computed. - * `model` [sklearn estimator that implements predict with ``return_std``]: + model : sklearn estimator that implements predict with ``return_std`` The fit estimator that approximates the function through the method ``predict``. It should have a ``return_std`` parameter that returns the standard deviation. - * `kappa`: [float, default 1.96 or 'inf']: + kappa : float or 'inf', optional (default=1.96) Controls how much of the variance in the predicted values should be taken into account. If set to be very high, then we are favouring exploration over exploitation and vice versa. @@ -113,17 +113,17 @@ def gaussian_lcb(X, model, kappa=1.96, return_grad=False): which is useful in a pure exploration setting. Useless if ``method`` is set to "LCB". - * `return_grad`: [boolean, optional]: + return_grad : boolean, optional (default=False) Whether or not to return the grad. Implemented only for the case where ``X`` is a single sample. Returns ------- - * `values`: [array-like, shape=(X.shape[0],)]: - Acquisition function values computed at X. + values : array-like, shape=[X.shape[0]] + Acquisition function values computed at ``X``. - * `grad`: [array-like, shape=(n_samples, n_features)]: - Gradient at X. + grad : array-like, shape=[n_samples, n_features] + Gradient at ``X``. """ # Compute posterior. with warnings.catch_warnings(): @@ -149,12 +149,12 @@ def gaussian_pi(X, model, y_opt=0.0, xi=0.01, return_grad=False): """ Use the probability of improvement to calculate the acquisition values. - The conditional probability `P(y=f(x) | x)`form a gaussian with a + The conditional probability ``P(y=f(x) | x)`` form a gaussian with a certain mean and standard deviation approximated by the model. The PI condition is derived by computing ``E[u(f(x))]`` where ``u(f(x)) = 1``, if ``f(x) < y_opt`` and ``u(f(x)) = 0``, - if``f(x) > y_opt``. + if ``f(x) > y_opt``. This means that the PI condition does not care about how "better" the predictions are than the previous values, since it gives an equal reward @@ -165,30 +165,33 @@ def gaussian_pi(X, model, y_opt=0.0, xi=0.01, return_grad=False): Parameters ---------- - * `X` [array-like, shape=(n_samples, n_features)]: + X : array-like, shape=[n_samples, n_features] Values where the acquisition function should be computed. - * `model` [sklearn estimator that implements predict with ``return_std``]: + model : sklearn estimator that implements predict with ``return_std`` The fit estimator that approximates the function through the method ``predict``. It should have a ``return_std`` parameter that returns the standard deviation. - * `y_opt` [float, default 0]: + y_opt : float, optional (default 0) Previous minimum value which we would like to improve upon. - * `xi`: [float, default=0.01]: + xi : float, optional (default=0.01) Controls how much improvement one wants over the previous best values. Useful only when ``method`` is set to "EI" - * `return_grad`: [boolean, optional]: + return_grad : boolean, optional (default=False) Whether or not to return the grad. Implemented only for the case where ``X`` is a single sample. Returns ------- - * `values`: [array-like, shape=(X.shape[0],)]: - Acquisition function values computed at X. + values : array-like, shape=[X.shape[0]] + Acquisition function values computed at ``X``. + + grad : array-like, shape=[n_samples, n_features] + Gradient at ``X``. """ with warnings.catch_warnings(): warnings.simplefilter("ignore") @@ -239,30 +242,33 @@ def gaussian_ei(X, model, y_opt=0.0, xi=0.01, return_grad=False): Parameters ---------- - * `X` [array-like, shape=(n_samples, n_features)]: + X : array-like, shape=[n_samples, n_features] Values where the acquisition function should be computed. - * `model` [sklearn estimator that implements predict with ``return_std``]: + model : sklearn estimator that implements predict with ``return_std`` The fit estimator that approximates the function through the method ``predict``. It should have a ``return_std`` parameter that returns the standard deviation. - * `y_opt` [float, default 0]: + y_opt : float, optional (default 0) Previous minimum value which we would like to improve upon. - * `xi`: [float, default=0.01]: + xi : float, optional (default=0.01) Controls how much improvement one wants over the previous best values. Useful only when ``method`` is set to "EI" - * `return_grad`: [boolean, optional]: + return_grad : boolean, optional (default=False) Whether or not to return the grad. Implemented only for the case where ``X`` is a single sample. Returns ------- - * `values`: [array-like, shape=(X.shape[0],)]: - Acquisition function values computed at X. + values : array-like, shape=[X.shape[0]] + Acquisition function values computed at ``X``. + + grad : array-like, shape=[n_samples, n_features] + Gradient at ``X``. """ with warnings.catch_warnings(): warnings.simplefilter("ignore") diff --git a/skopt/plots.py b/skopt/plots.py index 14f2586..3a71c76 100644 --- a/skopt/plots.py +++ b/skopt/plots.py @@ -15,28 +15,29 @@ def plot_convergence(*args, **kwargs): Parameters ---------- - * `args[i]` [`OptimizeResult`, list of `OptimizeResult`, or tuple]: + args[i] : ``OptimizeResult``, list of ``OptimizeResult``, or tuple The result(s) for which to plot the convergence trace. - - if `OptimizeResult`, then draw the corresponding single trace; - - if list of `OptimizeResult`, then draw the corresponding convergence - traces in transparency, along with the average convergence trace; - - if tuple, then `args[i][0]` should be a string label and `args[i][1]` - an `OptimizeResult` or a list of `OptimizeResult`. + - if ``OptimizeResult``, then draw the corresponding single trace; + - if list of ``OptimizeResult``, then draw the corresponding + convergence traces in transparency, along with the average + convergence trace; + - if tuple, then ``args[i][0]`` should be a string label and + ``args[i][1]`` an ``OptimizeResult`` or a list of ``OptimizeResult``. - * `ax` [`Axes`, optional]: + ax : `Axes`, optional (default=None) The matplotlib axes on which to draw the plot, or `None` to create a new one. - * `true_minimum` [float, optional]: + true_minimum : float, optional (default=None) The true minimum value of the function, if known. - * `yscale` [None or string, optional]: + yscale : None or string, optional (default=None) The scale for the y-axis. Returns ------- - * `ax`: [`Axes`]: + ax : ``Axes`` The matplotlib axes. """ # <3 legacy python @@ -147,58 +148,58 @@ def _format_scatter_plot_axes(ax, space, ylabel): def partial_dependence(space, model, i, j=None, sample_points=None, n_samples=250, n_points=40): - """Calculate the partial dependence for dimensions `i` and `j` with - respect to the objective value, as approximated by `model`. + """Calculate the partial dependence for dimensions ``i`` and ``j`` with + respect to the objective value, as approximated by ``model``. The partial dependence plot shows how the value of the dimensions - `i` and `j` influence the `model` predictions after "averaging out" + ``i`` and ``j`` influence the ``model`` predictions after "averaging out" the influence of all other dimensions. Parameters ---------- - * `space` [`Space`] + space : ``Space`` The parameter space over which the minimization was performed. - * `model` + model : skopt regressor Surrogate model for the objective function. - * `i` [int] + i : int The first dimension for which to calculate the partial dependence. - * `j` [int, default=None] + j : int, optional (default=None) The second dimension for which to calculate the partial dependence. - To calculate the 1D partial dependence on `i` alone set `j=None`. + To calculate the 1D partial dependence on ``i`` alone set ``j=None``. - * `sample_points` [np.array, shape=(n_points, n_dims), default=None] + sample_points : np.array, shape=[n_points, n_dims], optional (default=None) Randomly sampled and transformed points to use when averaging - the model function at each of the `n_points`. + the model function at each of the ``n_points``. - * `n_samples` [int, default=100] + n_samples : int, optional (default=100) Number of random samples to use for averaging the model function - at each of the `n_points`. Only used when `sample_points=None`. + at each of the ``n_points``. Only used when ``sample_points=None``. - * `n_points` [int, default=40] + n_points : int, optional (default=40) Number of points at which to evaluate the partial dependence - along each dimension `i` and `j`. + along each dimension ``i`` and ``j``. Returns ------- For 1D partial dependence: - * `xi`: [np.array]: + xi : np.array The points at which the partial dependence was evaluated. - * `yi`: [np.array]: - The value of the model at each point `xi`. + yi : np.array + The value of the model at each point ``xi``. For 2D partial dependence: - * `xi`: [np.array, shape=n_points]: + xi : np.array, shape=[n_points] The points at which the partial dependence was evaluated. - * `yi`: [np.array, shape=n_points]: + yi : np.array, shape=[n_points] The points at which the partial dependence was evaluated. - * `zi`: [np.array, shape=(n_points, n_points)]: - The value of the model at each point `(xi, yi)`. + zi : np.array, shape=[n_points, n_points] + The value of the model at each point ``(xi, yi)``. """ if sample_points is None: sample_points = space.transform(space.rvs(n_samples=n_samples)) @@ -243,43 +244,43 @@ def plot_objective(result, levels=10, n_points=40, n_samples=250, zscale='linear'): """Pairwise partial dependence plot of the objective function. - The diagonal shows the partial dependence for dimension `i` with + The diagonal shows the partial dependence for dimension ``i`` with respect to the objective function. The off-diagonal shows the - partial dependence for dimensions `i` and `j` with + partial dependence for dimensions ``i`` and ``j`` with respect to the objective function. The objective function is - approximated by `result.model.` + approximated by ``result.model``. Pairwise scatter plots of the points at which the objective function was directly evaluated are shown on the off-diagonal. A red point indicates the found minimum. - Note: search spaces that contain `Categorical` dimensions are + Note: search spaces that contain ``Categorical`` dimensions are currently not supported by this function. Parameters ---------- - * `result` [`OptimizeResult`] + result : `OptimizeResult`` The result for which to create the scatter plot matrix. - * `levels` [int, default=10] + levels : int, optional (default=10) Number of levels to draw on the contour plot, passed directly - to `plt.contour()`. + to ``plt.contour()``. - * `n_points` [int, default=40] + n_points : int, optional (default=40) Number of points at which to evaluate the partial dependence along each dimension. - * `n_samples` [int, default=250] + n_samples : int, optional (default=250) Number of random samples to use for averaging the model function - at each of the `n_points`. + at each of the ``n_points``. - * `zscale` [str, default='linear'] + zscale : str, optional (default='linear') Scale to use for the z axis of the contour plots. Either 'linear' or 'log'. Returns ------- - * `ax`: [`Axes`]: + ax : ``Axes`` The matplotlib axes. """ space = result.space @@ -337,20 +338,20 @@ def plot_evaluations(result, bins=20): The diagonal shows a histogram of sampled values for each dimension. A red point indicates the found minimum. - Note: search spaces that contain `Categorical` dimensions are + Note: search spaces that contain ``Categorical`` dimensions are currently not supported by this function. Parameters ---------- - * `result` [`OptimizeResult`] + result : ``OptimizeResult`` The result for which to create the scatter plot matrix. - * `bins` [int, bins=20]: + bins : int, optional (default=20) Number of bins to use for histograms on the diagonal. Returns ------- - * `ax`: [`Axes`]: + ax : ``Axes`` The matplotlib axes. """ space = result.space From 0862f9534801f9ed51b82904fdacba721ab58bf8 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Thu, 13 Jul 2017 07:56:08 +0200 Subject: [PATCH 11/18] Tweak BayesSearchCV docs --- skopt/searchcv.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/skopt/searchcv.py b/skopt/searchcv.py index 608fb9b..f288dc6 100644 --- a/skopt/searchcv.py +++ b/skopt/searchcv.py @@ -246,18 +246,13 @@ class BayesSearchCV(sk_model_sel.BaseSearchCV): The parameters selected are those that maximize the score of the held-out data, according to the scoring parameter. - If `n_jobs` was set to a value higher than one, the data is copied for each - parameter setting(and not `n_jobs` times). This is done for efficiency - reasons if individual jobs take very little time, but may raise errors if - the dataset is large and not enough memory is available. A workaround in - this case is to set `pre_dispatch`. Then, the memory is copied only - `pre_dispatch` many times. A reasonable value for `pre_dispatch` is `2 * - n_jobs`. - - See Also - -------- - :class:`GridSearchCV`: - Does exhaustive search over a grid of parameters. + If ``n_jobs`` was set to a value higher than one, the data is copied for + each parameter setting (and not ``n_jobs`` times). This is done for + efficiency reasons if individual jobs take very little time, but may raise + errors if the dataset is large and not enough memory is available. A + workaround in this case is to set ``pre_dispatch``. Then, the memory is + copied only ``pre_dispatch`` many times. A reasonable value for + ``pre_dispatch`` is ``2 * n_jobs``. """ From 79b56dbabf228ccc5d1f2f5cafcba76fc9e382cb Mon Sep 17 00:00:00 2001 From: Tim Head Date: Thu, 20 Jul 2017 19:39:54 +0200 Subject: [PATCH 12/18] Temporary commit to store state --- docs/ask-and-tell.ipynb | 364 ++++++++++++++++++++++++++++++++++++++++++++++++ docs/conf.py | 1 + docs/index.rst | 1 + 3 files changed, 366 insertions(+) create mode 100644 docs/ask-and-tell.ipynb diff --git a/docs/ask-and-tell.ipynb b/docs/ask-and-tell.ipynb new file mode 100644 index 0000000..9b20883 --- /dev/null +++ b/docs/ask-and-tell.ipynb @@ -0,0 +1,364 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Async optimization Loop\n", + "\n", + "Tim Head, February 2017." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "np.random.seed(1234)\n", + "\n", + "%matplotlib inline\n", + "import matplotlib.pyplot as plt\n", + "plt.set_cmap(\"viridis\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Bayesian optimization is used to tune parameters for walking robots or other experiments\n", + "that are not a simple (expensive) function call.\n", + "\n", + "They often follow a pattern a bit like this:\n", + "1. ask for a new set of parameters\n", + "1. walk to the experiment and program in the new parameters\n", + "1. observe the outcome of running the experiment\n", + "1. walk back to your laptop and tell the optimizer about the outcome\n", + "1. go to step 1\n", + "\n", + "A setup like this is difficult to implement with the `*_minimize()` function interface.\n", + "This is why `scikit-optimize` has a ask-and-tell interface that you can use when you want\n", + "to control the execution of the optimization loop.\n", + "\n", + "This notenook demonstrates how to use the ask and tell interface.\n", + "\n", + "\n", + "## The Setup\n", + "\n", + "We will use a simple 1D problem to illustrate the API. This is a\n", + "little bit artificial as you normally would not use the ask-and-tell\n", + "interface if you had a function you can call to evaluate the objective." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from skopt.learning import ExtraTreesRegressor\n", + "from skopt import Optimizer\n", + "\n", + "noise_level = 0.1\n", + "\n", + "# Our 1D toy problem, this is the function we are trying to\n", + "# minimize\n", + "def objective(x, noise_level=noise_level):\n", + " return np.sin(5 * x[0]) * (1 - np.tanh(x[0] ** 2)) + np.random.randn() * noise_level" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here a quick plot to visualize what the function looks like:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Plot f(x) + contours\n", + "x = np.linspace(-2, 2, 400).reshape(-1, 1)\n", + "fx = np.array([objective(x_i, noise_level=0.0) for x_i in x])\n", + "plt.plot(x, fx, \"r--\", label=\"True (unknown)\")\n", + "plt.fill(np.concatenate([x, x[::-1]]),\n", + " np.concatenate(([fx_i - 1.9600 * noise_level for fx_i in fx], \n", + " [fx_i + 1.9600 * noise_level for fx_i in fx[::-1]])),\n", + " alpha=.2, fc=\"r\", ec=\"None\")\n", + "plt.legend()\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we setup the `Optimizer` class. The arguments follow the meaning\n", + "and naming of the `*_minimize()` functions. An important difference\n", + "is that you do not pass the objective function to the optimizer." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "opt = Optimizer([(-2.0, 2.0)], \"ET\", acq_optimizer=\"sampling\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To obtain a suggestion for the point at which to evaluate the objective\n", + "you call the `ask()` method of `opt`:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[-1.3229420461664514]\n" + ] + } + ], + "source": [ + "next_x = opt.ask()\n", + "print(next_x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In a real world use case you would probably go away and use this parameter in your\n", + "experiment and come back a while later with the result. In this example we can\n", + "simply evaluate the objective function and report the value back to the\n", + "optimizer:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "f_val = objective(next_x)\n", + "opt.tell(next_x, f_val)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Like `*_minimize()` the first few points are random suggestions as there is no data\n", + "yet with which to fit a surrogate model." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "for i in range(9):\n", + " next_x = opt.ask()\n", + " f_val = objective(next_x)\n", + " opt.tell(next_x, f_val)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now plot the random suggestions and the first model that has been fit:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\nAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from skopt.acquisition import gaussian_ei\n", + "\n", + "def plot_optimizer(opt, x, fx):\n", + " model = opt.models[-1]\n", + " x_model = opt.space.transform(x.tolist())\n", + "\n", + " # Plot true function.\n", + " plt.plot(x, fx, \"r--\", label=\"True (unknown)\")\n", + " plt.fill(np.concatenate([x, x[::-1]]),\n", + " np.concatenate([fx - 1.9600 * noise_level, \n", + " fx[::-1] + 1.9600 * noise_level]),\n", + " alpha=.2, fc=\"r\", ec=\"None\")\n", + "\n", + " # Plot Model(x) + contours\n", + " y_pred, sigma = model.predict(x_model, return_std=True)\n", + " plt.plot(x, y_pred, \"g--\", label=r\"$\\mu(x)$\")\n", + " plt.fill(np.concatenate([x, x[::-1]]),\n", + " np.concatenate([y_pred - 1.9600 * sigma, \n", + " (y_pred + 1.9600 * sigma)[::-1]]),\n", + " alpha=.2, fc=\"g\", ec=\"None\")\n", + "\n", + " # Plot sampled points\n", + " plt.plot(opt.Xi, opt.yi,\n", + " \"r.\", markersize=8, label=\"Observations\")\n", + "\n", + " acq = gaussian_ei(x_model, model, y_opt=np.min(opt.yi))\n", + " # shift down to make a better plot\n", + " acq = 4*acq - 2\n", + " plt.plot(x, acq, \"b\", label=\"EI(x)\")\n", + " plt.fill_between(x.ravel(), -2.0, acq.ravel(), alpha=0.3, color='blue')\n", + " \n", + " # Adjust plot layout\n", + " plt.grid()\n", + " plt.legend(loc='best')\n", + " \n", + "plot_optimizer(opt, x, fx)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us sample a few more points and plot the optimizer again:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "image/png": "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\no0axefNmAN5++20KCwtRVS5cuMC6devIzMxskN/27dsZOXJkh38Po2kCqgmIyK3A/wAZwElgm6re\nJCI9gb+o6s2edDcC/43jdFao6tJm8gz7msDGjRsjYuTNZavz7Fkn9nB1CzEFevS4ZIhpILSnPcO5\nJvC3v/2NnTt3snjx4iavl5eXs2zZMp/XG/OLX/yC5cuXB1NipyHsZgyr6jpgXRPnDwM31zveAAwI\npCzD8JKUBAMHwoEDcO7cpddFnJFAPWxN/2BQXFzMbbfd5vN6amoq6enpHD9+nPQWhuBu2bKFG264\nIdgSjQCwtYOMyObECWe7cMFpJkpOhu7dId7/pSDCgXCuCfhDbW0tf/nLX7jjjjt8pqmpqWHZsmU8\n8IDNF20r7VETMCdgGGFApDsBfzhy5AgpKSl06dK5l9kIhHDvGO40RMqwPtMZXCJFZ7iSlZVlDiAM\nMSdgGIbRibHmIMMIAzpDc5ARONYcZBiGYQQVcwJtIFLahk1ncIkUnYbRGswJGIZhdGKsT8AwwgDr\nEzD8wfoEDMMISxYtWsSMGTNCLaPVjB8/npdffjnUMkKKOYE2ECltw6YzuESKzvZi5cqVDB48mKSk\nJLKzs7nrrrs4deqU93rzsaVCz6JFiy5Z/uLvf/97RDqvYGJOwDCMFnn88cd58MEHefzxx6moqKC4\nuJjS0lLGjh1LdUsL+QWJmpqaDimn06GqYbU5kgyjc+Hzub94UXXOHNUxY5zPixdbn3mAeVRUVGjX\nrl117dq1Dc6fOXNGe/TooS+88IIWFBTolClTdOrUqZqcnKzXXnutlpSUeNMuXbpUe/XqpcnJyTpw\n4EB9//33VVW1trZWlyxZov3799eMjAydOnWqlpeXq6qq2+1WEdEVK1ZoTk6Ojho1Sm+66Sb905/+\n1EDHkCFD9PXXX1dV1XvuuUf79OmjLpdLhw4dqps2bVJV1Q0bNmhcXJzGxcVp165dNS8vT1VVR48e\nrStWrPBq+f3vf6+5ubmamZmpM2fO1FOnTjXQ8uKLL2pOTo52795dFy9e7NWwefNmHTp0qLpcLs3K\nytL77ruvVTb2F1/Pied82965bb2xvTZzAkZnxOdzP2eOanS081ONjla9++7WZx5gHhs2bNDY2Fit\nqam55NrMmTM1Pz9fCwoKNDY2Vl977TWtrq7WZcuWab9+/bS6ulr37t2rffr00SNHjqiqamlpqR44\n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\nRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "for i in range(10):\n", + " next_x = opt.ask()\n", + " f_val = objective(next_x)\n", + " opt.tell(next_x, f_val)\n", + " \n", + "plot_optimizer(opt, x, fx)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By using the `Optimizer` class directly you get control over the optimization loop.\n", + "\n", + "You can also pickle your `Optimizer` instance if you want to end the process running it\n", + "and resume it later. This is handy if your experiment takes a very long time and you\n", + "want to shutdown your computer in the meantime:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import pickle\n", + "\n", + "with open('my-optimizer.pkl', 'wb') as f:\n", + " pickle.dump(opt, f)\n", + "\n", + "with open('my-optimizer.pkl', 'rb') as f:\n", + " opt_restored = pickle.load(f)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/docs/conf.py b/docs/conf.py index 920b959..a437f52 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -37,6 +37,7 @@ 'sphinx.ext.viewcode', 'sphinx.ext.githubpages', 'numpydoc', + 'nbsphinx', ] # Add any paths that contain templates here, relative to this directory. diff --git a/docs/index.rst b/docs/index.rst index a7588d1..3c22943 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -26,3 +26,4 @@ Plot made using ``skopt.plots.plot_objective``. intro api/index + ask-and-tell.ipynb From cd0f1c4e7888b4285a628da966c25bf4480bb86f Mon Sep 17 00:00:00 2001 From: Tim Head Date: Tue, 1 Aug 2017 19:21:38 +0200 Subject: [PATCH 13/18] Add callback documentation --- docs/api/callbacks.rst | 23 +++ docs/api/index.rst | 1 + docs/api/space.rst | 8 +- docs/ask-and-tell.ipynb | 364 ------------------------------------------------ docs/index.rst | 1 - skopt/callbacks.py | 12 +- skopt/space/space.py | 114 +++++++-------- 7 files changed, 94 insertions(+), 429 deletions(-) create mode 100644 docs/api/callbacks.rst delete mode 100644 docs/ask-and-tell.ipynb diff --git a/docs/api/callbacks.rst b/docs/api/callbacks.rst new file mode 100644 index 0000000..f92b41e --- /dev/null +++ b/docs/api/callbacks.rst @@ -0,0 +1,23 @@ +.. _callback-functions: + +``skopt.callbacks``, callback functions +============================================ + +Overview +-------- + +.. currentmodule:: skopt.callbacks + +.. autosummary:: + + DeltaXStopper + DeltaYStopper + TimerCallback + VerboseCallback + + +Details +------- + +.. automodule:: skopt.callbacks + :members: diff --git a/docs/api/index.rst b/docs/api/index.rst index 1211c47..eb3e4fa 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -11,6 +11,7 @@ Details on the complete API of scikit-optimize. optimizer bayessearchcv acquisition + callbacks plots space utils diff --git a/docs/api/space.rst b/docs/api/space.rst index c7f4ba6..4517329 100644 --- a/docs/api/space.rst +++ b/docs/api/space.rst @@ -21,5 +21,9 @@ Overview Details ------- -.. automodule:: skopt.space - :members: +.. autofunction:: skopt.space.check_dimension +.. autoclass:: skopt.space.Space +.. autoclass:: skopt.space.Categorical +.. autoclass:: skopt.space.Integer +.. autoclass:: skopt.space.Real +.. autoclass:: skopt.space.Dimension diff --git a/docs/ask-and-tell.ipynb b/docs/ask-and-tell.ipynb deleted file mode 100644 index 9b20883..0000000 --- a/docs/ask-and-tell.ipynb +++ /dev/null @@ -1,364 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Async optimization Loop\n", - "\n", - "Tim Head, February 2017." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import numpy as np\n", - "np.random.seed(1234)\n", - "\n", - "%matplotlib inline\n", - "import matplotlib.pyplot as plt\n", - "plt.set_cmap(\"viridis\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Bayesian optimization is used to tune parameters for walking robots or other experiments\n", - "that are not a simple (expensive) function call.\n", - "\n", - "They often follow a pattern a bit like this:\n", - "1. ask for a new set of parameters\n", - "1. walk to the experiment and program in the new parameters\n", - "1. observe the outcome of running the experiment\n", - "1. walk back to your laptop and tell the optimizer about the outcome\n", - "1. go to step 1\n", - "\n", - "A setup like this is difficult to implement with the `*_minimize()` function interface.\n", - "This is why `scikit-optimize` has a ask-and-tell interface that you can use when you want\n", - "to control the execution of the optimization loop.\n", - "\n", - "This notenook demonstrates how to use the ask and tell interface.\n", - "\n", - "\n", - "## The Setup\n", - "\n", - "We will use a simple 1D problem to illustrate the API. This is a\n", - "little bit artificial as you normally would not use the ask-and-tell\n", - "interface if you had a function you can call to evaluate the objective." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "from skopt.learning import ExtraTreesRegressor\n", - "from skopt import Optimizer\n", - "\n", - "noise_level = 0.1\n", - "\n", - "# Our 1D toy problem, this is the function we are trying to\n", - "# minimize\n", - "def objective(x, noise_level=noise_level):\n", - " return np.sin(5 * x[0]) * (1 - np.tanh(x[0] ** 2)) + np.random.randn() * noise_level" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here a quick plot to visualize what the function looks like:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Plot f(x) + contours\n", - "x = np.linspace(-2, 2, 400).reshape(-1, 1)\n", - "fx = np.array([objective(x_i, noise_level=0.0) for x_i in x])\n", - "plt.plot(x, fx, \"r--\", label=\"True (unknown)\")\n", - "plt.fill(np.concatenate([x, x[::-1]]),\n", - " np.concatenate(([fx_i - 1.9600 * noise_level for fx_i in fx], \n", - " [fx_i + 1.9600 * noise_level for fx_i in fx[::-1]])),\n", - " alpha=.2, fc=\"r\", ec=\"None\")\n", - "plt.legend()\n", - "plt.grid()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we setup the `Optimizer` class. The arguments follow the meaning\n", - "and naming of the `*_minimize()` functions. An important difference\n", - "is that you do not pass the objective function to the optimizer." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "opt = Optimizer([(-2.0, 2.0)], \"ET\", acq_optimizer=\"sampling\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To obtain a suggestion for the point at which to evaluate the objective\n", - "you call the `ask()` method of `opt`:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[-1.3229420461664514]\n" - ] - } - ], - "source": [ - "next_x = opt.ask()\n", - "print(next_x)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In a real world use case you would probably go away and use this parameter in your\n", - "experiment and come back a while later with the result. In this example we can\n", - "simply evaluate the objective function and report the value back to the\n", - "optimizer:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "f_val = objective(next_x)\n", - "opt.tell(next_x, f_val)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Like `*_minimize()` the first few points are random suggestions as there is no data\n", - "yet with which to fit a surrogate model." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "for i in range(9):\n", - " next_x = opt.ask()\n", - " f_val = objective(next_x)\n", - " opt.tell(next_x, f_val)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can now plot the random suggestions and the first model that has been fit:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\nAElFTkSuQmCC\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from skopt.acquisition import gaussian_ei\n", - "\n", - "def plot_optimizer(opt, x, fx):\n", - " model = opt.models[-1]\n", - " x_model = opt.space.transform(x.tolist())\n", - "\n", - " # Plot true function.\n", - " plt.plot(x, fx, \"r--\", label=\"True (unknown)\")\n", - " plt.fill(np.concatenate([x, x[::-1]]),\n", - " np.concatenate([fx - 1.9600 * noise_level, \n", - " fx[::-1] + 1.9600 * noise_level]),\n", - " alpha=.2, fc=\"r\", ec=\"None\")\n", - "\n", - " # Plot Model(x) + contours\n", - " y_pred, sigma = model.predict(x_model, return_std=True)\n", - " plt.plot(x, y_pred, \"g--\", label=r\"$\\mu(x)$\")\n", - " plt.fill(np.concatenate([x, x[::-1]]),\n", - " np.concatenate([y_pred - 1.9600 * sigma, \n", - " (y_pred + 1.9600 * sigma)[::-1]]),\n", - " alpha=.2, fc=\"g\", ec=\"None\")\n", - "\n", - " # Plot sampled points\n", - " plt.plot(opt.Xi, opt.yi,\n", - " \"r.\", markersize=8, label=\"Observations\")\n", - "\n", - " acq = gaussian_ei(x_model, model, y_opt=np.min(opt.yi))\n", - " # shift down to make a better plot\n", - " acq = 4*acq - 2\n", - " plt.plot(x, acq, \"b\", label=\"EI(x)\")\n", - " plt.fill_between(x.ravel(), -2.0, acq.ravel(), alpha=0.3, color='blue')\n", - " \n", - " # Adjust plot layout\n", - " plt.grid()\n", - " plt.legend(loc='best')\n", - " \n", - "plot_optimizer(opt, x, fx)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us sample a few more points and plot the optimizer again:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\no0axefNmAN5++20KCwtRVS5cuMC6devIzMxskN/27dsZOXJkh38Po2kCqgmIyK3A/wAZwElgm6re\nJCI9gb+o6s2edDcC/43jdFao6tJm8gz7msDGjRsjYuTNZavz7Fkn9nB1CzEFevS4ZIhpILSnPcO5\nJvC3v/2NnTt3snjx4iavl5eXs2zZMp/XG/OLX/yC5cuXB1NipyHsZgyr6jpgXRPnDwM31zveAAwI\npCzD8JKUBAMHwoEDcO7cpddFnJFAPWxN/2BQXFzMbbfd5vN6amoq6enpHD9+nPQWhuBu2bKFG264\nIdgSjQCwtYOMyObECWe7cMFpJkpOhu7dId7/pSDCgXCuCfhDbW0tf/nLX7jjjjt8pqmpqWHZsmU8\n8IDNF20r7VETMCdgGGFApDsBfzhy5AgpKSl06dK5l9kIhHDvGO40RMqwPtMZXCJFZ7iSlZVlDiAM\nMSdgGIbRibHmIMMIAzpDc5ARONYcZBiGYQQVcwJtIFLahk1ncIkUnYbRGswJGIZhdGKsT8AwwgDr\nEzD8wfoEDMMISxYtWsSMGTNCLaPVjB8/npdffjnUMkKKOYE2ECltw6YzuESKzvZi5cqVDB48mKSk\nJLKzs7nrrrs4deqU93rzsaVCz6JFiy5Z/uLvf/97RDqvYGJOwDCMFnn88cd58MEHefzxx6moqKC4\nuJjS0lLGjh1LdUsL+QWJmpqaDimn06GqYbU5kgyjc+Hzub94UXXOHNUxY5zPixdbn3mAeVRUVGjX\nrl117dq1Dc6fOXNGe/TooS+88IIWFBTolClTdOrUqZqcnKzXXnutlpSUeNMuXbpUe/XqpcnJyTpw\n4EB9//33VVW1trZWlyxZov3799eMjAydOnWqlpeXq6qq2+1WEdEVK1ZoTk6Ojho1Sm+66Sb905/+\n1EDHkCFD9PXXX1dV1XvuuUf79OmjLpdLhw4dqps2bVJV1Q0bNmhcXJzGxcVp165dNS8vT1VVR48e\nrStWrPBq+f3vf6+5ubmamZmpM2fO1FOnTjXQ8uKLL2pOTo52795dFy9e7NWwefNmHTp0qLpcLs3K\nytL77ruvVTb2F1/Pied82965bb2xvTZzAkZnxOdzP2eOanS081ONjla9++7WZx5gHhs2bNDY2Fit\nqam55NrMmTM1Pz9fCwoKNDY2Vl977TWtrq7WZcuWab9+/bS6ulr37t2rffr00SNHjqiqamlpqR44\n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\nRU5ErkJggg==\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "for i in range(10):\n", - " next_x = opt.ask()\n", - " f_val = objective(next_x)\n", - " opt.tell(next_x, f_val)\n", - " \n", - "plot_optimizer(opt, x, fx)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "By using the `Optimizer` class directly you get control over the optimization loop.\n", - "\n", - "You can also pickle your `Optimizer` instance if you want to end the process running it\n", - "and resume it later. This is handy if your experiment takes a very long time and you\n", - "want to shutdown your computer in the meantime:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "import pickle\n", - "\n", - "with open('my-optimizer.pkl', 'wb') as f:\n", - " pickle.dump(opt, f)\n", - "\n", - "with open('my-optimizer.pkl', 'rb') as f:\n", - " opt_restored = pickle.load(f)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.5.2" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/docs/index.rst b/docs/index.rst index 3c22943..a7588d1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -26,4 +26,3 @@ Plot made using ``skopt.plots.plot_objective``. intro api/index - ask-and-tell.ipynb diff --git a/skopt/callbacks.py b/skopt/callbacks.py index 048ceac..d379409 100644 --- a/skopt/callbacks.py +++ b/skopt/callbacks.py @@ -12,6 +12,8 @@ Early stopping callbacks ------------------------ * DeltaXStopper +* DeltaYStopper +* TimerCallback """ from collections import Callable from time import time @@ -144,7 +146,7 @@ def __call__(self, res): self._time = time() -class EarlyStopper(object): +class _EarlyStopper(object): """Decide to continue or not given the results so far. The optimization procedure will be stopped if the callback returns True. @@ -179,14 +181,14 @@ def _criterion(self, result): " by subclasses of EarlyStopper.") -class DeltaXStopper(EarlyStopper): +class DeltaXStopper(_EarlyStopper): """Stop the optimization when |x1 - x2| < `delta` If the last two positions at which the objective has been evaluated are less than `delta` apart stop the optimization procedure. """ def __init__(self, delta): - super(EarlyStopper, self).__init__() + super(_EarlyStopper, self).__init__() self.delta = delta def _criterion(self, result): @@ -198,14 +200,14 @@ def _criterion(self, result): return None -class DeltaYStopper(EarlyStopper): +class DeltaYStopper(_EarlyStopper): """Stop the optimization if the `n_best` minima are within `delta` Stop the optimizer if the absolute difference between the `n_best` objective values is less than `delta`. """ def __init__(self, delta, n_best=5): - super(EarlyStopper, self).__init__() + super(_EarlyStopper, self).__init__() self.delta = delta self.n_best = n_best diff --git a/skopt/space/space.py b/skopt/space/space.py index f5b51bb..f0cbb9a 100644 --- a/skopt/space/space.py +++ b/skopt/space/space.py @@ -145,32 +145,32 @@ def _uniform_inclusive(loc=0.0, scale=1.0): class Real(Dimension): - def __init__(self, low, high, prior="uniform", transform=None): - """Search space dimension that can take on any real value. + """Search space dimension that can take on any real value. - Parameters - ---------- - low : float - Lower bound (inclusive). - - high : float - Upper bound (inclusive). - - prior : 'uniform' or 'log-uniform', optional, (default='uniform') - Distribution to use when sampling random points for this dimension. - - If ``uniform``, points are sampled uniformly between the lower - and upper bounds. - - If ``log-uniform``, points are sampled uniformly between - ``log10(lower)`` and ``log10(upper)``. - - transform : 'identity' or 'normalize', optional (default='identity') - The following transformations are supported. - - - 'identity', the transformed space is the same as the - original space. - - 'normalize', the transformed space is scaled to be between - 0 and 1. - """ + Parameters + ---------- + low : float + Lower bound (inclusive). + + high : float + Upper bound (inclusive). + + prior : 'uniform' or 'log-uniform', optional, (default='uniform') + Distribution to use when sampling random points for this dimension. + - If ``uniform``, points are sampled uniformly between the lower + and upper bounds. + - If ``log-uniform``, points are sampled uniformly between + ``log10(lower)`` and ``log10(upper)``. + + transform : 'identity' or 'normalize', optional (default='identity') + The following transformations are supported. + + - 'identity', the transformed space is the same as the + original space. + - 'normalize', the transformed space is scaled to be between + 0 and 1. + """ + def __init__(self, low, high, prior="uniform", transform=None): self.low = low self.high = high self.prior = prior @@ -261,25 +261,25 @@ def distance(self, a, b): class Integer(Dimension): - def __init__(self, low, high, transform=None): - """Search space dimension that can take on integer values. + """Search space dimension that can take on integer values. - Parameters - ---------- - low : int - Lower bound (inclusive). + Parameters + ---------- + low : int + Lower bound (inclusive). - high : int - Upper bound (inclusive). + high : int + Upper bound (inclusive). - transform : 'identity' or 'normalize', optional (default='identity') - The following transformations are supported. + transform : 'identity' or 'normalize', optional (default='identity') + The following transformations are supported. - - "identity", the transformed space is the same as the - original space. - - "normalize", the transformed space is scaled to be between - 0 and 1. - """ + - "identity", the transformed space is the same as the + original space. + - "normalize", the transformed space is scaled to be between + 0 and 1. + """ + def __init__(self, low, high, transform=None): self.low = low self.high = high @@ -346,24 +346,24 @@ def distance(self, a, b): class Categorical(Dimension): - def __init__(self, categories, prior=None, transform=None): - """Search space dimension that can take on categorical values. + """Search space dimension that can take on categorical values. - Parameters - ---------- - categories : list, shape=[n_categories] - Sequence of possible categories. - - prior : list, shape=[categories], optional (default=None) - Prior probabilities for each category. By default all categories - are equally likely. - - transform : 'onehot' or 'identity', optional (default='onehot') - - 'identity', the transformed space is the same as the original - space. - - 'onehot', the transformed space is a one-hot encoded - representation of the original space. - """ + Parameters + ---------- + categories : list, shape=[n_categories] + Sequence of possible categories. + + prior : list, shape=[categories], optional (default=None) + Prior probabilities for each category. By default all categories + are equally likely. + + transform : 'onehot' or 'identity', optional (default='onehot') + - 'identity', the transformed space is the same as the original + space. + - 'onehot', the transformed space is a one-hot encoded + representation of the original space. + """ + def __init__(self, categories, prior=None, transform=None): self.categories = categories if transform is None: From 3f74485879935465be7a9911c871e34baee9120d Mon Sep 17 00:00:00 2001 From: Tim Head Date: Tue, 1 Aug 2017 22:02:39 +0200 Subject: [PATCH 14/18] Add nbsphinx dependency --- build_tools/circle/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_tools/circle/install.sh b/build_tools/circle/install.sh index 0f8b4b6..596866b 100644 --- a/build_tools/circle/install.sh +++ b/build_tools/circle/install.sh @@ -37,7 +37,7 @@ pip install -e. export SKOPT_HOME=$(pwd) conda install --yes jupyter -pip install sphinx numpydoc +pip install sphinx numpydoc nbsphinx # importing matplotlib once builds the font caches. This avoids # having warnings in our example notebooks From d459314d4f8e7b8c08431f804a340f9dceea18a5 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Tue, 1 Aug 2017 22:29:00 +0200 Subject: [PATCH 15/18] Fix up callbacks module --- skopt/callbacks.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/skopt/callbacks.py b/skopt/callbacks.py index d379409..04cc0a7 100644 --- a/skopt/callbacks.py +++ b/skopt/callbacks.py @@ -11,6 +11,7 @@ Early stopping callbacks ------------------------ +* DeadlineStopper * DeltaXStopper * DeltaYStopper * TimerCallback @@ -224,7 +225,7 @@ def _criterion(self, result): return None -class DeadlineStopper(EarlyStopper): +class DeadlineStopper(_EarlyStopper): """ Stop the optimization before running out of a fixed budget of time. From 0ecde29f64692a7992f63ee133cd94e3824bbb08 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Wed, 2 Aug 2017 07:52:06 +0200 Subject: [PATCH 16/18] Tweak callbacks.py docstrings --- skopt/callbacks.py | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/skopt/callbacks.py b/skopt/callbacks.py index 04cc0a7..6870c15 100644 --- a/skopt/callbacks.py +++ b/skopt/callbacks.py @@ -2,7 +2,7 @@ Callbacks are callables which are invoked after each iteration of the optimizer and are passed the results "so far". Callbacks can monitor progress, or stop -the optimization early by returning `True`. +the optimization early by returning ``True``. Monitoring callbacks -------------------- @@ -47,19 +47,19 @@ class VerboseCallback(object): Parameters ---------- - * `n_init` [int, optional]: + n_total : int + Total number of func calls. + + n_init : int, optional (default=0) Number of points provided by the user which are yet to be evaluated. This is equal to `len(x0)` when `y0` is None - * `n_random` [int, optional]: + n_random : int, optional (default=0) Number of points randomly chosen. - * `n_total` [int]: - Total number of func calls. - Attributes ---------- - * `iter_no`: [int]: + iter_no : int Number of iterations of the optimization routine. """ @@ -100,7 +100,7 @@ def __call__(self, res): """ Parameters ---------- - * `res` [`OptimizeResult`, scipy object]: + res : ``OptimizeResult``, scipy object The optimization as a OptimizeResult object. """ time_taken = time() - self._start_time @@ -123,13 +123,13 @@ class TimerCallback(object): """ Log the elapsed time between each iteration of the minimization loop. - The time for each iteration is stored in the `iter_time` attribute which + The time for each iteration is stored in the ``iter_time`` attribute which you can inspect after the minimization has completed. Attributes ---------- - * `iter_time`: [list, shape=(n_iter,)]: - `iter_time[i-1]` gives the time taken to complete iteration `i` + iter_time : list, shape=(n_iter,) + ``iter_time[i-1]`` gives the time taken to complete iteration ``i`` """ def __init__(self): self._time = time() @@ -139,7 +139,7 @@ def __call__(self, res): """ Parameters ---------- - * `res` [`OptimizeResult`, scipy object]: + res : ``OptimizeResult``, scipy object The optimization as a OptimizeResult object. """ elapsed_time = time() - self._time @@ -156,7 +156,7 @@ def __call__(self, result): """ Parameters ---------- - * `result` [`OptimizeResult`, scipy object]: + res : ``OptimizeResult``, scipy object The optimization as a OptimizeResult object. """ return self._criterion(result) @@ -183,10 +183,10 @@ def _criterion(self, result): class DeltaXStopper(_EarlyStopper): - """Stop the optimization when |x1 - x2| < `delta` + """Stop the optimization when |x1 - x2| < ``delta`` If the last two positions at which the objective has been evaluated - are less than `delta` apart stop the optimization procedure. + are less than ``delta`` apart stop the optimization procedure. """ def __init__(self, delta): super(_EarlyStopper, self).__init__() @@ -202,10 +202,10 @@ def _criterion(self, result): class DeltaYStopper(_EarlyStopper): - """Stop the optimization if the `n_best` minima are within `delta` + """Stop the optimization if the ``n_best`` minima are within ``delta`` - Stop the optimizer if the absolute difference between the `n_best` - objective values is less than `delta`. + Stop the optimizer if the absolute difference between the ``n_best`` + objective values is less than ``delta``. """ def __init__(self, delta, n_best=5): super(_EarlyStopper, self).__init__() @@ -226,18 +226,18 @@ def _criterion(self, result): class DeadlineStopper(_EarlyStopper): - """ - Stop the optimization before running out of a fixed budget of time. + """Stop the optimization before running out of a fixed budget of time. - Attributes + Parameters ---------- - * `iter_time`: [list, shape=(n_iter,)]: - `iter_time[i-1]` gives the time taken to complete iteration `i` + total_time : float + Time (in seconds) that the optimization must finish within. - Parameters + Attributes ---------- - * `total_time`: fixed budget of time (seconds) that the optimization must - finish within. + iter_time : list, shape=(n_iter,) + ``iter_time[i-1]`` gives the time taken to complete iteration ``i`` + """ def __init__(self, total_time): super(DeadlineStopper, self).__init__() From 124f80b6f8cffa6673441da3fe301613deb380aa Mon Sep 17 00:00:00 2001 From: Tim Head Date: Wed, 2 Aug 2017 08:10:42 +0200 Subject: [PATCH 17/18] Tweak gp_minimize doc string --- skopt/optimizer/gp.py | 166 +++++++++++++++++++++++++------------------------- 1 file changed, 84 insertions(+), 82 deletions(-) diff --git a/skopt/optimizer/gp.py b/skopt/optimizer/gp.py index 5f52d6d..2d0dfdf 100644 --- a/skopt/optimizer/gp.py +++ b/skopt/optimizer/gp.py @@ -31,37 +31,37 @@ def gp_minimize(func, dimensions, base_estimator=None, next parameter to evaluate can be made by the acquisition function over the Gaussian prior which is much quicker to evaluate. - The total number of evaluations, `n_calls`, are performed like the - following. If `x0` is provided but not `y0`, then the elements of `x0` - are first evaluated, followed by `n_random_starts` evaluations. - Finally, `n_calls - len(x0) - n_random_starts` evaluations are - made guided by the surrogate model. If `x0` and `y0` are both - provided then `n_random_starts` evaluations are first made then - `n_calls - n_random_starts` subsequent evaluations are made + The total number of evaluations, ``n_calls``, are performed like the + following. If ``x0`` is provided but not ``y0``, then the elements of ``x0`` + are first evaluated, followed by ``n_random_starts`` evaluations. + Finally, ``n_calls - len(x0) - n_random_starts`` evaluations are + made guided by the surrogate model. If ``x0`` and ``y0`` are both + provided then ``n_random_starts`` evaluations are first made then + ``n_calls - n_random_starts`` subsequent evaluations are made guided by the surrogate model. Parameters ---------- - * `func` [callable]: + func : callable Function to minimize. Should take a array of parameters and return the function values. - * `dimensions` [list, shape=(n_dims,)]: + dimensions : list, shape=(n_dims,) List of search space dimensions. Each search dimension can be defined either as - - a `(upper_bound, lower_bound)` tuple (for `Real` or `Integer` + - a ``(lower_bound, upper_bound)`` tuple (for ``Real`` or ``Integer`` dimensions), - - a `(upper_bound, lower_bound, "prior")` tuple (for `Real` + - a ``(lower_bound, upper_bound, "prior")`` tuple (for ``Real`` dimensions), - - as a list of categories (for `Categorical` dimensions), or - - an instance of a `Dimension` object (`Real`, `Integer` or - `Categorical`). + - as a list of categories (for ``Categorical`` dimensions), or + - an instance of a ``Dimension`` object (``Real``, ``Integer`` or + ``Categorical``). - NOTE: The upper and lower bounds are inclusive for `Integer` + NOTE: The upper and lower bounds are inclusive for ``Integer`` dimensions. - * `base_estimator` [a Gaussian process estimator]: + base_estimator : a Gaussian process estimator The Gaussian process estimator to use for optimization. By default, a Matern kernel is used with the following hyperparameters tuned. @@ -70,106 +70,108 @@ def gp_minimize(func, dimensions, base_estimator=None, - Noise that is added to the matern kernel. The noise is assumed to be iid gaussian. - * `n_calls` [int, default=100]: - Number of calls to `func`. + n_calls : int (default=100) + Number of calls to ``func``. - * `n_random_starts` [int, default=10]: - Number of evaluations of `func` with random points before - approximating it with `base_estimator`. + n_random_starts : int (default=10) + Number of evaluations of ``func`` with random points before + approximating it with ``base_estimator``. - * `acq_func` [string, default=`"EI"`]: + acq_func : string, (default="EI") Function to minimize over the gaussian prior. Can be either - - `"LCB"` for lower confidence bound. - - `"EI"` for negative expected improvement. - - `"PI"` for negative probability of improvement. - - `"gp_hedge"` Probabilistically choose one of the above three + - "LCB" for lower confidence bound. + - "EI" for negative expected improvement. + - "PI" for negative probability of improvement. + - "gp_hedge" Probabilistically choose one of the above three acquisition functions at every iteration. The weightage - given to these gains can be set by `\eta` through `acq_func_kwargs`. - - The gains `g_i` are initialized to zero. + given to these gains can be set by ``\eta`` through + ``acq_func_kwargs``. + - The gains ``g_i`` are initialized to zero. - At every iteration, - Each acquisition function is optimised independently to - propose an candidate point `X_i`. - - Out of all these candidate points, the next point `X_best` is - chosen by `softmax(\eta g_i)` - - After fitting the surrogate model with `(X_best, y_best)`, - the gains are updated such that `g_i -= \mu(X_i)` - - `"EIps"` for negated expected improvement per second to take into + propose an candidate point ``X_i``. + - Out of all these candidate points, the next point ``X_best`` + is chosen by ``softmax(\eta g_i)``. + - After fitting the surrogate model with ``(X_best, y_best)``, + the gains are updated such that ``g_i -= \mu(X_i)`` + - "EIps" for negated expected improvement per second to take into account the function compute time. Then, the objective function is assumed to return two values, the first being the objective value and the second being the time taken in seconds. - - `"PIps"` for negated probability of improvement per second. The + - "PIps" for negated probability of improvement per second. The return type of the objective function is assumed to be similar to - that of `"EIps + that of "EIps". - * `acq_optimizer` [string, `"sampling"` or `"lbfgs"`, default=`"lbfgs"`]: + acq_optimizer : string, "sampling" or "lbfgs" (default="lbfgs") Method to minimize the acquistion function. The fit model - is updated with the optimal value obtained by optimizing `acq_func` - with `acq_optimizer`. + is updated with the optimal value obtained by optimizing ``acq_func`` + with ``acq_optimizer``. - The `acq_func` is computed at `n_points` sampled randomly. + The ``acq_func`` is computed at ``n_points`` sampled randomly. - - If set to `"auto"`, then `acq_optimizer` is configured on the + - If set to "auto", then ``acq_optimizer`` is configured on the basis of the space searched over. - If the space is Categorical then this is set to be "sampling"`. - - If set to `"sampling"`, then the point among these `n_points` - where the `acq_func` is minimum is the next candidate minimum. - - If set to `"lbfgs"`, then - - The `n_restarts_optimizer` no. of points which the acquisition + If the space is ``Categorical`` then this is set to be "sampling". + - If set to "sampling", then the point among these ``n_points`` + where the ``acq_func`` is minimum is the next candidate minimum. + - If set to "lbfgs", then + - The ``n_restarts_optimizer`` no. of points which the acquisition function is least are taken as start points. - - `"lbfgs"` is run for 20 iterations with these points as initial + - "lbfgs" is run for 20 iterations with these points as initial points to find local minima. - The optimal of these local minima is used to update the prior. - * `x0` [list, list of lists or `None`]: + x0 : list, list of lists or ``None`` Initial input points. - If it is a list of lists, use it as a list of input points. - If it is a list, use it as a single initial input point. - - If it is `None`, no initial input points are used. + - If it is ``None``, no initial input points are used. - * `y0` [list, scalar or `None`] + y0 : list, scalar or ``None`` Evaluation of initial input points. - If it is a list, then it corresponds to evaluations of the function - at each element of `x0` : the i-th element of `y0` corresponds - to the function evaluated at the i-th element of `x0`. + at each element of ``x0`` : the i-th element of ``y0`` corresponds + to the function evaluated at the i-th element of ``x0``. - If it is a scalar, then it corresponds to the evaluation of the - function at `x0`. - - If it is None and `x0` is provided, then the function is evaluated - at each element of `x0`. + function at ``x0``. + - If it is None and ``x0`` is provided, then the function is evaluated + at each element of ``x0``. - * `random_state` [int, RandomState instance, or None (default)]: + random_state : int, RandomState instance or None, optional (default=None) Set random state to something other than None for reproducible results. - * `verbose` [boolean, default=False]: + verbose : boolean (default=False) Control the verbosity. It is advised to set the verbosity to True for long optimization runs. - * `callback` [callable, list of callables, optional] - If callable then `callback(res)` is called after each call to `func`. - If list of callables, then each callable in the list is called. + callback : callable, list of callables, optional + If callable then ``callback(res)`` is called after each call to + ``func``. If list of callables, then each callable in the list is + called. - * `n_points` [int, default=10000]: + n_points : int, optional (default=10000) Number of points to sample to determine the next "best" point. - Useless if acq_optimizer is set to `"lbfgs"`. + Useless if acq_optimizer is set to ``lbfgs``. - * `n_restarts_optimizer` [int, default=5]: - The number of restarts of the optimizer when `acq_optimizer` - is `"lbfgs"`. + n_restarts_optimizer : int, optional (default=5) + The number of restarts of the optimizer when ``acq_optimizer`` + is "lbfgs". - * `kappa` [float, default=1.96]: + kappa : float, optional (default=1.96) Controls how much of the variance in the predicted values should be taken into account. If set to be very high, then we are favouring exploration over exploitation and vice versa. - Used when the acquisition is `"LCB"`. + Used when the acquisition is "LCB". - * `xi` [float, default=0.01]: + xi : float, optional (default=0.01) Controls how much improvement one wants over the previous best - values. Used when the acquisition is either `"EI"` or `"PI"`. + values. Used when the acquisition is either "EI" or "PI". - * `noise` [float, default="gaussian"]: + noise : float, optional (default="gaussian") - Use noise="gaussian" if the objective returns noisy observations. The noise of each observation is assumed to be iid with mean zero and a fixed variance. @@ -178,28 +180,28 @@ def gp_minimize(func, dimensions, base_estimator=None, - Set this to a value close to zero (1e-10) if the function is noise-free. Setting to zero might cause stability issues. - * `n_jobs` [int, default=1] + n_jobs : int, optional (default=1) Number of cores to run in parallel while running the lbfgs optimizations over the acquisition function. Valid only - when `acq_optimizer` is set to "lbfgs." - Defaults to 1 core. If `n_jobs=-1`, then number of jobs is set + when ``acq_optimizer`` is set to "lbfgs". + Defaults to 1 core. If ``n_jobs=-1``, then number of jobs is set to number of cores. Returns ------- - * `res` [`OptimizeResult`, scipy object]: + res : ``OptimizeResult``, scipy object The optimization result returned as a OptimizeResult object. Important attributes are: - - `x` [list]: location of the minimum. - - `fun` [float]: function value at the minimum. - - `models`: surrogate models used for each iteration. - - `x_iters` [list of lists]: location of function evaluation for each + - ``x`` [list]: location of the minimum. + - ``fun`` [float]: function value at the minimum. + - ``models``: surrogate models used for each iteration. + - ``x_iters`` [list of lists]: location of function evaluation for each iteration. - - `func_vals` [array]: function value for each iteration. - - `space` [Space]: the optimization space. - - `specs` [dict]`: the call specifications. - - `rng` [RandomState instance]: State of the random state + - ``func_vals`` [array]: function value for each iteration. + - ``space`` [Space]: the optimization space. + - ``specs`` [dict]: the call specifications. + - ``rng`` [RandomState instance]: State of the random state at the end of minimization. For more details related to the OptimizeResult object, refer From 81eff29f1b3d7c5fb4e68782fb32b1b4e72fee26 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Wed, 2 Aug 2017 08:19:35 +0200 Subject: [PATCH 18/18] Tweak GBRT docstrings. --- skopt/optimizer/gbrt.py | 139 +++++++++++++++++++++++++++--------------------- 1 file changed, 79 insertions(+), 60 deletions(-) diff --git a/skopt/optimizer/gbrt.py b/skopt/optimizer/gbrt.py index c368f60..f9eae53 100644 --- a/skopt/optimizer/gbrt.py +++ b/skopt/optimizer/gbrt.py @@ -14,121 +14,140 @@ def gbrt_minimize(func, dimensions, base_estimator=None, """Sequential optimization using gradient boosted trees. Gradient boosted regression trees are used to model the (very) - expensive to evaluate function `func`. The model is improved + expensive to evaluate function ``func``. The model is improved by sequentially evaluating the expensive function at the next best point. Thereby finding the minimum of `func` with as few evaluations as possible. - The total number of evaluations, `n_calls`, are performed like the - following. If `x0` is provided but not `y0`, then the elements of `x0` - are first evaluated, followed by `n_random_starts` evaluations. - Finally, `n_calls - len(x0) - n_random_starts` evaluations are - made guided by the surrogate model. If `x0` and `y0` are both - provided then `n_random_starts` evaluations are first made then - `n_calls - n_random_starts` subsequent evaluations are made + The total number of evaluations, ``n_calls``, are performed like the + following. If ``x0`` is provided but not ``y0``, then the elements of + ``x0`` are first evaluated, followed by ``n_random_starts`` evaluations. + Finally, ``n_calls - len(x0) - n_random_starts`` evaluations are + made guided by the surrogate model. If ``x0`` and ``y0`` are both + provided then ``n_random_starts`` evaluations are first made then + ``n_calls - n_random_starts`` subsequent evaluations are made guided by the surrogate model. Parameters ---------- - * `func` [callable]: + func : callable Function to minimize. Should take a array of parameters and return the function values. - * `dimensions` [list, shape=(n_dims,)]: + dimensions : list, shape=(n_dims,) List of search space dimensions. Each search dimension can be defined either as - - a `(upper_bound, lower_bound)` tuple (for `Real` or `Integer` + - a ``(lower_bound, upper_bound)`` tuple (for ``Real`` or ``Integer`` dimensions), - - a `(upper_bound, lower_bound, "prior")` tuple (for `Real` + - a ``(lower_bound, upper_bound, "prior")`` tuple (for ``Real`` dimensions), - - as a list of categories (for `Categorical` dimensions), or - - an instance of a `Dimension` object (`Real`, `Integer` or - `Categorical`). + - as a list of categories (for ``Categorical`` dimensions), or + - an instance of a ``Dimension`` object (``Real``, ``Integer`` or + ``Categorical``). - * `base_estimator` [`GradientBoostingQuantileRegressor`]: - The regressor to use as surrogate model + NOTE: The upper and lower bounds are inclusive for ``Integer`` + dimensions. - * `n_calls` [int, default=100]: - Number of calls to `func`. + base_estimator : ``GradientBoostingQuantileRegressor`` + The regressor to use as surrogate model. - * `n_random_starts` [int, default=10]: - Number of evaluations of `func` with random points before - approximating it with `base_estimator`. + n_calls : int, optional (default=100) + Number of calls to ``func``. - * `acq_func` [string, default=`"LCB"`]: + n_random_starts : int, optional (default=10) + Number of evaluations of ``func`` with random points before + approximating it with ``base_estimator``. + + acq_func : string, optional (default="LCB") Function to minimize over the forest posterior. Can be either - - `"LCB"` for lower confidence bound. - - `"EI"` for negative expected improvement. - - `"PI"` for negative probability of improvement. - - ``"EIps"`` for negated expected improvement per second to take into + - "LCB" for lower confidence bound. + - "EI" for negative expected improvement. + - "PI" for negative probability of improvement. + - "gp_hedge" Probabilistically choose one of the above three + acquisition functions at every iteration. The weightage + given to these gains can be set by ``\eta`` through + ``acq_func_kwargs``. + - The gains ``g_i`` are initialized to zero. + - At every iteration, + - Each acquisition function is optimised independently to + propose an candidate point ``X_i``. + - Out of all these candidate points, the next point ``X_best`` + is chosen by ``softmax(\eta g_i)``. + - After fitting the surrogate model with ``(X_best, y_best)``, + the gains are updated such that ``g_i -= \mu(X_i)`` + - "EIps" for negated expected improvement per second to take into account the function compute time. Then, the objective function is assumed to return two values, the first being the objective value and the second being the time taken. - - `"PIps"` for negated probability of improvement per second. + - "PIps" for negated probability of improvement per second. - * `x0` [list, list of lists or `None`]: + x0 : list, list of lists or ``None`` Initial input points. - If it is a list of lists, use it as a list of input points. - If it is a list, use it as a single initial input point. - - If it is `None`, no initial input points are used. + - If it is ``None``, no initial input points are used. - * `y0` [list, scalar or `None`]: + y0 : list, scalar or ``None`` Evaluation of initial input points. - If it is a list, then it corresponds to evaluations of the function - at each element of `x0` : the i-th element of `y0` corresponds - to the function evaluated at the i-th element of `x0`. + at each element of ``x0`` : the i-th element of ``y0`` corresponds + to the function evaluated at the i-th element of ``x0``. - If it is a scalar, then it corresponds to the evaluation of the - function at `x0`. - - If it is None and `x0` is provided, then the function is evaluated - at each element of `x0`. + function at ``x0``. + - If it is None and ``x0`` is provided, then the function is evaluated + at each element of ``x0``. - * `random_state` [int, RandomState instance, or None (default)]: + random_state : int, RandomState instance or None, optional (default=None) Set random state to something other than None for reproducible results. - * `verbose` [boolean, default=False]: + verbose : boolean (default=False) Control the verbosity. It is advised to set the verbosity to True for long optimization runs. - * `callback` [callable, optional] - If provided, then `callback(res)` is called after call to func. - - * `n_points` [int, default=10000]: - Number of points to sample when minimizing the acquisition function. + callback : callable, list of callables, optional + If callable then ``callback(res)`` is called after each call to + ``func``. If list of callables, then each callable in the list is + called. - * `xi` [float, default=0.01]: - Controls how much improvement one wants over the previous best - values. Used when the acquisition is either `"EI"` or `"PI"`. + n_points : int, optional (default=10000) + Number of points to sample to determine the next "best" point. + Useless if acq_optimizer is set to ``lbfgs``. - * `kappa` [float, default=1.96]: + kappa : float, optional (default=1.96) Controls how much of the variance in the predicted values should be taken into account. If set to be very high, then we are favouring exploration over exploitation and vice versa. - Used when the acquisition is `"LCB"`. + Used when the acquisition is "LCB". + + xi : float, optional (default=0.01) + Controls how much improvement one wants over the previous best + values. Used when the acquisition is either "EI" or "PI". - * `n_jobs` [int, default=1]: - The number of jobs to run in parallel for `fit` and `predict`. - If -1, then the number of jobs is set to the number of cores. + n_jobs : int, optional (default=1) + Number of cores used to parallize fitting of ``base_estimator``. + Defaults to 1 core. If ``n_jobs=-1``, then number of jobs is set + to number of cores. Returns ------- - * `res` [`OptimizeResult`, scipy object]: + res : ``OptimizeResult``, scipy object The optimization result returned as a OptimizeResult object. Important attributes are: - - `x` [list]: location of the minimum. - - `fun` [float]: function value at the minimum. - - `models`: surrogate models used for each iteration. - - `x_iters` [list of lists]: location of function evaluation for each + - ``x`` [list]: location of the minimum. + - ``fun`` [float]: function value at the minimum. + - ``models``: surrogate models used for each iteration. + - ``x_iters`` [list of lists]: location of function evaluation for each iteration. - - `func_vals` [array]: function value for each iteration. - - `space` [Space]: the optimization space. - - `specs` [dict]`: the call specifications. - - `rng` [RandomState instance]: State of the random state + - ``func_vals`` [array]: function value for each iteration. + - ``space`` [Space]: the optimization space. + - ``specs`` [dict]: the call specifications. + - ``rng`` [RandomState instance]: State of the random state at the end of minimization. For more details related to the OptimizeResult object, refer