Skip to content

Commit 7393d12

Browse files
committed
Pushing the docs to 0.7/ for branch: 0.7.X, commit 972d2a891cfb3bfe0290a8a4d5994852e871989c
1 parent d8b3004 commit 7393d12

File tree

382 files changed

+88612
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

382 files changed

+88612
-0
lines changed

0.7/.buildinfo

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Sphinx build info version 1
2+
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
3+
config: 16b82a1d7c55e2684c87b351530d164b
4+
tags: 645f666f9bcd5a90fca523b33c5a78b7

0.7/.nojekyll

Whitespace-only changes.
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"metadata": {
7+
"collapsed": false
8+
},
9+
"outputs": [],
10+
"source": [
11+
"%matplotlib inline"
12+
]
13+
},
14+
{
15+
"cell_type": "markdown",
16+
"metadata": {},
17+
"source": [
18+
"\n==================================\nBayesian optimization with `skopt`\n==================================\n\nGilles Louppe, Manoj Kumar July 2016.\nReformatted by Holger Nahrstaedt 2020\n\n.. currentmodule:: skopt\n\nProblem statement\n-----------------\n\nWe are interested in solving\n\n\\begin{align}x^* = arg \\min_x f(x)\\end{align}\n\nunder the constraints that\n\n- $f$ is a black box for which no closed form is known\n (nor its gradients);\n- $f$ is expensive to evaluate;\n- and evaluations of $y = f(x)$ may be noisy.\n\n**Disclaimer.** If you do not have these constraints, then there\nis certainly a better optimization algorithm than Bayesian optimization.\n\n\nBayesian optimization loop\n--------------------------\n\nFor $t=1:T$:\n\n1. Given observations $(x_i, y_i=f(x_i))$ for $i=1:t$, build a\n probabilistic model for the objective $f$. Integrate out all\n possible true functions, using Gaussian process regression.\n\n2. optimize a cheap acquisition/utility function $u$ based on the posterior\n distribution for sampling the next point.\n\n .. math::\n x_{t+1} = arg \\min_x u(x)\n\n Exploit uncertainty to balance exploration against exploitation.\n\n3. Sample the next observation $y_{t+1}$ at $x_{t+1}$.\n\n\nAcquisition functions\n---------------------\n\nAcquisition functions $u(x)$ specify which sample $x$: should be\ntried next:\n\n- Expected improvement (default):\n $-EI(x) = -\\mathbb{E} [f(x) - f(x_t^+)]$\n\n- Lower confidence bound: $LCB(x) = \\mu_{GP}(x) + \\kappa \\sigma_{GP}(x)$\n\n- Probability of improvement: $-PI(x) = -P(f(x) \\geq f(x_t^+) + \\kappa)$\n\nwhere $x_t^+$ is the best point observed so far.\n\nIn most cases, acquisition functions provide knobs (e.g., $\\kappa$) for\ncontrolling the exploration-exploitation trade-off.\n- Search in regions where $\\mu_{GP}(x)$ is high (exploitation)\n- Probe regions where uncertainty $\\sigma_{GP}(x)$ is high (exploration)\n"
19+
]
20+
},
21+
{
22+
"cell_type": "code",
23+
"execution_count": null,
24+
"metadata": {
25+
"collapsed": false
26+
},
27+
"outputs": [],
28+
"source": [
29+
"print(__doc__)\n\nimport numpy as np\nnp.random.seed(237)\nimport matplotlib.pyplot as plt"
30+
]
31+
},
32+
{
33+
"cell_type": "markdown",
34+
"metadata": {},
35+
"source": [
36+
"Toy example\n-----------\n\nLet assume the following noisy function $f$:\n\n"
37+
]
38+
},
39+
{
40+
"cell_type": "code",
41+
"execution_count": null,
42+
"metadata": {
43+
"collapsed": false
44+
},
45+
"outputs": [],
46+
"source": [
47+
"noise_level = 0.1\n\ndef f(x, noise_level=noise_level):\n return np.sin(5 * x[0]) * (1 - np.tanh(x[0] ** 2))\\\n + np.random.randn() * noise_level"
48+
]
49+
},
50+
{
51+
"cell_type": "markdown",
52+
"metadata": {},
53+
"source": [
54+
"**Note.** In `skopt`, functions $f$ are assumed to take as input a 1D\nvector $x$: represented as an array-like and to return a scalar\n$f(x)$:.\n\n"
55+
]
56+
},
57+
{
58+
"cell_type": "code",
59+
"execution_count": null,
60+
"metadata": {
61+
"collapsed": false
62+
},
63+
"outputs": [],
64+
"source": [
65+
"# Plot f(x) + contours\nx = np.linspace(-2, 2, 400).reshape(-1, 1)\nfx = [f(x_i, noise_level=0.0) for x_i in x]\nplt.plot(x, fx, \"r--\", label=\"True (unknown)\")\nplt.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\")\nplt.legend()\nplt.grid()\nplt.show()"
66+
]
67+
},
68+
{
69+
"cell_type": "markdown",
70+
"metadata": {},
71+
"source": [
72+
"Bayesian optimization based on gaussian process regression is implemented in\n:class:`gp_minimize` and can be carried out as follows:\n\n"
73+
]
74+
},
75+
{
76+
"cell_type": "code",
77+
"execution_count": null,
78+
"metadata": {
79+
"collapsed": false
80+
},
81+
"outputs": [],
82+
"source": [
83+
"from skopt import gp_minimize\n\nres = gp_minimize(f, # the function to minimize\n [(-2.0, 2.0)], # the bounds on each dimension of x\n acq_func=\"EI\", # the acquisition function\n n_calls=15, # the number of evaluations of f\n n_random_starts=5, # the number of random initialization points\n noise=0.1**2, # the noise level (optional)\n random_state=1234) # the random seed"
84+
]
85+
},
86+
{
87+
"cell_type": "markdown",
88+
"metadata": {},
89+
"source": [
90+
"Accordingly, the approximated minimum is found to be:\n\n"
91+
]
92+
},
93+
{
94+
"cell_type": "code",
95+
"execution_count": null,
96+
"metadata": {
97+
"collapsed": false
98+
},
99+
"outputs": [],
100+
"source": [
101+
"\"x^*=%.4f, f(x^*)=%.4f\" % (res.x[0], res.fun)"
102+
]
103+
},
104+
{
105+
"cell_type": "markdown",
106+
"metadata": {},
107+
"source": [
108+
"For further inspection of the results, attributes of the `res` named tuple\nprovide the following information:\n\n- `x` [float]: location of the minimum.\n- `fun` [float]: function value at the minimum.\n- `models`: surrogate models used for each iteration.\n- `x_iters` [array]:\n location of function evaluation for each iteration.\n- `func_vals` [array]: function value for each iteration.\n- `space` [Space]: the optimization space.\n- `specs` [dict]: parameters passed to the function.\n\n"
109+
]
110+
},
111+
{
112+
"cell_type": "code",
113+
"execution_count": null,
114+
"metadata": {
115+
"collapsed": false
116+
},
117+
"outputs": [],
118+
"source": [
119+
"print(res)"
120+
]
121+
},
122+
{
123+
"cell_type": "markdown",
124+
"metadata": {},
125+
"source": [
126+
"Together these attributes can be used to visually inspect the results of the\nminimization, such as the convergence trace or the acquisition function at\nthe last iteration:\n\n"
127+
]
128+
},
129+
{
130+
"cell_type": "code",
131+
"execution_count": null,
132+
"metadata": {
133+
"collapsed": false
134+
},
135+
"outputs": [],
136+
"source": [
137+
"from skopt.plots import plot_convergence\nplot_convergence(res);"
138+
]
139+
},
140+
{
141+
"cell_type": "markdown",
142+
"metadata": {},
143+
"source": [
144+
"Let us now visually examine\n\n1. The approximation of the fit gp model to the original function.\n2. The acquisition values that determine the next point to be queried.\n\n"
145+
]
146+
},
147+
{
148+
"cell_type": "code",
149+
"execution_count": null,
150+
"metadata": {
151+
"collapsed": false
152+
},
153+
"outputs": [],
154+
"source": [
155+
"from skopt.acquisition import gaussian_ei\n\nplt.rcParams[\"figure.figsize\"] = (8, 14)\n\nx = np.linspace(-2, 2, 400).reshape(-1, 1)\nx_gp = res.space.transform(x.tolist())\nfx = np.array([f(x_i, noise_level=0.0) for x_i in x])"
156+
]
157+
},
158+
{
159+
"cell_type": "markdown",
160+
"metadata": {},
161+
"source": [
162+
"Plot the 5 iterations following the 5 random points\n\n"
163+
]
164+
},
165+
{
166+
"cell_type": "code",
167+
"execution_count": null,
168+
"metadata": {
169+
"collapsed": false
170+
},
171+
"outputs": [],
172+
"source": [
173+
"for n_iter in range(5):\n gp = res.models[n_iter]\n curr_x_iters = res.x_iters[:5+n_iter]\n curr_func_vals = res.func_vals[:5+n_iter]\n\n # Plot true function.\n plt.subplot(5, 2, 2*n_iter+1)\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 GP(x) + contours\n y_pred, sigma = gp.predict(x_gp, return_std=True)\n plt.plot(x, y_pred, \"g--\", label=r\"$\\mu_{GP}(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(curr_x_iters, curr_func_vals,\n \"r.\", markersize=8, label=\"Observations\")\n\n # Adjust plot layout\n plt.grid()\n\n if n_iter == 0:\n plt.legend(loc=\"best\", prop={'size': 6}, numpoints=1)\n\n if n_iter != 4:\n plt.tick_params(axis='x', which='both', bottom='off',\n top='off', labelbottom='off')\n\n # Plot EI(x)\n plt.subplot(5, 2, 2*n_iter+2)\n acq = gaussian_ei(x_gp, gp, y_opt=np.min(curr_func_vals))\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 next_x = res.x_iters[5+n_iter]\n next_acq = gaussian_ei(res.space.transform([next_x]), gp,\n y_opt=np.min(curr_func_vals))\n plt.plot(next_x, next_acq, \"bo\", markersize=6, label=\"Next query point\")\n\n # Adjust plot layout\n plt.ylim(0, 0.1)\n plt.grid()\n\n if n_iter == 0:\n plt.legend(loc=\"best\", prop={'size': 6}, numpoints=1)\n\n if n_iter != 4:\n plt.tick_params(axis='x', which='both', bottom='off',\n top='off', labelbottom='off')\n\nplt.show()"
174+
]
175+
},
176+
{
177+
"cell_type": "markdown",
178+
"metadata": {},
179+
"source": [
180+
"The first column shows the following:\n\n1. The true function.\n2. The approximation to the original function by the gaussian process model\n3. How sure the GP is about the function.\n\nThe second column shows the acquisition function values after every\nsurrogate model is fit. It is possible that we do not choose the global\nminimum but a local minimum depending on the minimizer used to minimize\nthe acquisition function.\n\nAt the points closer to the points previously evaluated at, the variance\ndips to zero.\n\nFinally, as we increase the number of points, the GP model approaches\nthe actual function. The final few points are clustered around the minimum\nbecause the GP does not gain anything more by further exploration:\n\n"
181+
]
182+
},
183+
{
184+
"cell_type": "code",
185+
"execution_count": null,
186+
"metadata": {
187+
"collapsed": false
188+
},
189+
"outputs": [],
190+
"source": [
191+
"plt.rcParams[\"figure.figsize\"] = (6, 4)\n\n# Plot f(x) + contours\nx = np.linspace(-2, 2, 400).reshape(-1, 1)\nx_gp = res.space.transform(x.tolist())\n\nfx = [f(x_i, noise_level=0.0) for x_i in x]\nplt.plot(x, fx, \"r--\", label=\"True (unknown)\")\nplt.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\n# Plot GP(x) + contours\ngp = res.models[-1]\ny_pred, sigma = gp.predict(x_gp, return_std=True)\n\nplt.plot(x, y_pred, \"g--\", label=r\"$\\mu_{GP}(x)$\")\nplt.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\nplt.plot(res.x_iters,\n res.func_vals,\n \"r.\", markersize=15, label=\"Observations\")\n\nplt.title(r\"$x^* = %.4f, f(x^*) = %.4f$\" % (res.x[0], res.fun))\nplt.legend(loc=\"best\", prop={'size': 8}, numpoints=1)\nplt.grid()\n\nplt.show()"
192+
]
193+
}
194+
],
195+
"metadata": {
196+
"kernelspec": {
197+
"display_name": "Python 3",
198+
"language": "python",
199+
"name": "python3"
200+
},
201+
"language_info": {
202+
"codemirror_mode": {
203+
"name": "ipython",
204+
"version": 3
205+
},
206+
"file_extension": ".py",
207+
"mimetype": "text/x-python",
208+
"name": "python",
209+
"nbconvert_exporter": "python",
210+
"pygments_lexer": "ipython3",
211+
"version": "3.8.1"
212+
}
213+
},
214+
"nbformat": 4,
215+
"nbformat_minor": 0
216+
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
"""
2+
===========================================
3+
Store and load `skopt` optimization results
4+
===========================================
5+
6+
Mikhail Pak, October 2016.
7+
Reformatted by Holger Nahrstaedt 2020
8+
9+
.. currentmodule:: skopt
10+
11+
Problem statement
12+
=================
13+
14+
We often want to store optimization results in a file. This can be useful,
15+
for example,
16+
17+
* if you want to share your results with colleagues;
18+
* if you want to archive and/or document your work;
19+
* or if you want to postprocess your results in a different Python instance or on an another computer.
20+
21+
The process of converting an object into a byte stream that can be stored in
22+
a file is called _serialization_.
23+
Conversely, _deserialization_ means loading an object from a byte stream.
24+
25+
**Warning:** Deserialization is not secure against malicious or erroneous
26+
code. Never load serialized data from untrusted or unauthenticated sources!
27+
28+
"""
29+
print(__doc__)
30+
import numpy as np
31+
import os
32+
import sys
33+
34+
# The followings are hacks to allow sphinx-gallery to run the example.
35+
sys.path.insert(0, os.getcwd())
36+
main_dir = os.path.basename(sys.modules['__main__'].__file__)
37+
IS_RUN_WITH_SPHINX_GALLERY = main_dir != os.getcwd()
38+
39+
#############################################################################
40+
# Simple example
41+
# ==============
42+
#
43+
# We will use the same optimization problem as in the
44+
# :ref:`sphx_glr_auto_examples_bayesian-optimization.py` notebook:
45+
46+
from skopt import gp_minimize
47+
noise_level = 0.1
48+
49+
if IS_RUN_WITH_SPHINX_GALLERY:
50+
# When this example is run with sphinx gallery, it breaks the pickling
51+
# capacity for multiprocessing backend so we have to modify the way we
52+
# define our functions. This has nothing to do with the example.
53+
from utils import obj_fun
54+
else:
55+
def obj_fun(x, noise_level=noise_level):
56+
return np.sin(5 * x[0]) * (1 - np.tanh(x[0] ** 2)) + np.random.randn() * noise_level
57+
58+
res = gp_minimize(obj_fun, # the function to minimize
59+
[(-2.0, 2.0)], # the bounds on each dimension of x
60+
x0=[0.], # the starting point
61+
acq_func="LCB", # the acquisition function (optional)
62+
n_calls=15, # the number of evaluations of f including at x0
63+
n_random_starts=0, # the number of random initialization points
64+
random_state=777)
65+
66+
#############################################################################
67+
# As long as your Python session is active, you can access all the
68+
# optimization results via the `res` object.
69+
#
70+
# So how can you store this data in a file? `skopt` conveniently provides
71+
# functions :class:`skopt.dump` and :class:`skopt.load` that handle this for you.
72+
# These functions are essentially thin wrappers around the
73+
# `joblib <https://joblib.readthedocs.io/en/latest/>`_ module's :obj:`joblib.dump` and :obj:`joblib.load`.
74+
#
75+
# We will now show how to use :class:`skopt.dump` and :class:`skopt.load` for storing
76+
# and loading results.
77+
#
78+
# Using `skopt.dump()` and `skopt.load()`
79+
# =======================================
80+
#
81+
# For storing optimization results into a file, call the :class:`skopt.dump`
82+
# function:
83+
84+
from skopt import dump, load
85+
86+
dump(res, 'result.pkl')
87+
88+
#############################################################################
89+
# And load from file using :class:`skopt.load`:
90+
91+
res_loaded = load('result.pkl')
92+
93+
res_loaded.fun
94+
95+
#############################################################################
96+
# You can fine-tune the serialization and deserialization process by calling
97+
# :class:`skopt.dump` and :class:`skopt.load` with additional keyword arguments. See the
98+
# `joblib <https://joblib.readthedocs.io/en/latest/>`_ documentation
99+
# :obj:`joblib.dump` and
100+
# :obj:`joblib.load` for the additional parameters.
101+
#
102+
# For instance, you can specify the compression algorithm and compression
103+
# level (highest in this case):
104+
105+
dump(res, 'result.gz', compress=9)
106+
107+
from os.path import getsize
108+
print('Without compression: {} bytes'.format(getsize('result.pkl')))
109+
print('Compressed with gz: {} bytes'.format(getsize('result.gz')))
110+
111+
#############################################################################
112+
# Unserializable objective functions
113+
# ----------------------------------
114+
#
115+
# Notice that if your objective function is non-trivial (e.g. it calls MATLAB
116+
# engine from Python), it might be not serializable and :class:`skopt.dump` will
117+
# raise an exception when you try to store the optimization results.
118+
# In this case you should disable storing the objective function by calling
119+
# :class:`skopt.dump` with the keyword argument `store_objective=False`:
120+
121+
dump(res, 'result_without_objective.pkl', store_objective=False)
122+
123+
#############################################################################
124+
# Notice that the entry `'func'` is absent in the loaded object but is still
125+
# present in the local variable:
126+
127+
128+
res_loaded_without_objective = load('result_without_objective.pkl')
129+
130+
print('Loaded object: ', res_loaded_without_objective.specs['args'].keys())
131+
print('Local variable:', res.specs['args'].keys())
132+
133+
#############################################################################
134+
# Possible problems
135+
# =================
136+
#
137+
# * **Python versions incompatibility:** In general, objects serialized in
138+
# Python 2 cannot be deserialized in Python 3 and vice versa.
139+
# * **Security issues:** Once again, do not load any files from untrusted
140+
# sources.
141+
# * **Extremely large results objects:** If your optimization results object
142+
#
143+
# is extremely large, calling :class:`skopt.dump` with `store_objective=False` might
144+
# cause performance issues. This is due to creation of a deep copy without the
145+
# objective function. If the objective function it is not critical to you, you
146+
# can simply delete it before calling :class:`skopt.dump`. In this case, no deep
147+
# copy is created:
148+
149+
del res.specs['args']['func']
150+
151+
dump(res, 'result_without_objective_2.pkl')

0 commit comments

Comments
 (0)