From da7a823081fd604031a72fb9e7ef14233c1883c8 Mon Sep 17 00:00:00 2001 From: Etienne Kintzler Date: Sun, 15 Nov 2020 13:27:23 +0100 Subject: [PATCH 01/14] [WIP] first layout for bandits classes --- benchmarks/Bandits_for_online_learning.ipynb | 469 +++++++++++++++++++ river/expert/__init__.py | 14 +- river/expert/bandit.py | 263 +++++++++++ 3 files changed, 745 insertions(+), 1 deletion(-) create mode 100644 benchmarks/Bandits_for_online_learning.ipynb create mode 100644 river/expert/bandit.py diff --git a/benchmarks/Bandits_for_online_learning.ipynb b/benchmarks/Bandits_for_online_learning.ipynb new file mode 100644 index 0000000000..86e11f92ec --- /dev/null +++ b/benchmarks/Bandits_for_online_learning.ipynb @@ -0,0 +1,469 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from collections import namedtuple\n", + "import itertools \n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "import tqdm\n", + "\n", + "from river import (\n", + " optim,\n", + " datasets,\n", + " preprocessing,\n", + " linear_model,\n", + " metrics,\n", + " compose\n", + " )\n", + "from river.stream import iter_sklearn_dataset\n", + "from river.expert import (\n", + " EpsilonGreedyBandit,\n", + " UCBBandit,\n", + " Exp3Bandit,\n", + " RandomBandit,\n", + " OracleBandit\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "\n", + "def gen_xy_numpy(N=1000, p=1, intercept=0.0, seed=None, drift=False):\n", + " N = int(N)\n", + " \n", + " if seed:\n", + " np.random.seed(seed)\n", + "\n", + " beta = np.random.normal(size=p, scale=2)\n", + "\n", + " x_arr = np.random.uniform(size=(N, p))\n", + " noise = np.random.normal(size=N, scale=0.15)\n", + " xb = intercept + np.sum(x_arr*beta, axis=1) \n", + " \n", + " if drift:\n", + " tier = N // 3\n", + " xb[tier:(2 * tier)] *= -1\n", + " xb[(2 * tier):] *= -1\n", + " beta *= -1\n", + " \n", + " y_arr = xb + noise\n", + "\n", + " return x_arr, y_arr, beta\n", + "\n", + "\n", + "Dataset = namedtuple(\"dat\", [\"target\", \"data\", \"feature_names\", \"beta\"])\n", + "\n", + "\n", + "def gen_dataset(**kwargs):\n", + " x_arr, y_arr, beta = gen_xy_numpy(**kwargs)\n", + " dataset = Dataset(y_arr, x_arr, [\"x{}\".format(i) for i in range(p)], beta)\n", + " return dataset\n", + "\n", + "\n", + "def gen_stream(dataset=None, take=None):\n", + " if dataset is None:\n", + " dataset = gen_dataset()\n", + " \n", + " gen = iter_sklearn_dataset(dataset)\n", + " \n", + " if take:\n", + " return itertools.islice(gen, take)\n", + " else:\n", + " return gen\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Studying loss behavior" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Paper on rewards scaling : \n", + "\n", + " - [Learning values across many orders of magnitude](https://arxiv.org/pdf/1602.07714.pdf)\n", + " \n", + " - [Stack message](https://datascience.stackexchange.com/questions/20098/why-do-we-normalize-the-discounted-rewards-when-doing-policy-gradient-reinforcem)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "def test():\n", + " \n", + " sc = preprocessing.MinMaxScaler()\n", + " \n", + " def compute_reward(y_pred, y_true, power=2):\n", + " loss = np.power(np.abs(y_pred - y_true), power)\n", + " loss_d = dict(l=loss)\n", + " loss = sc.learn_one(loss_d).transform_one(loss_d)[\"l\"]\n", + " return (1 / (1+ loss))\n", + " return 1 - loss\n", + " \n", + " return compute_reward" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "def compute_reward(y_pred, y_true, power=2):\n", + " loss = np.power(np.abs(y_pred - y_true), power)\n", + " return 1/ (1 + np.sqrt(loss))\n", + "\n", + "limit = 30\n", + "round_factor = 3\n", + "x = np.arange(-limit, limit, 0.25)\n", + "y = np.arange(-limit, limit, 0.25)\n", + "xx, yy = np.meshgrid(x, y, sparse=True)\n", + "\n", + "f = test()\n", + "z = compute_reward(xx, yy, power=1)\n", + "z_df = (pd.DataFrame(z)\n", + " .set_index(np.round(x, round_factor))\n", + " .rename(columns={\n", + " i:val for (i, val) in enumerate(np.round(y, round_factor))\n", + " }))\n", + "\n", + "f, ax = plt.subplots(figsize=(9, 6))\n", + "ax = sns.heatmap(z_df)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dataset generation" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "N = 1e5\n", + "p = 20\n", + "dataset = gen_dataset(p=p, N=N, intercept=.5, drift=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Training and bandits" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "l2_val=[1e-6, 1e-4, 1e-2, 1e-1, 1e-0, 2, 3]\n", + "optimz = [optim.SGD, optim.Adam]" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "from itertools import product\n", + "\n", + "def get_models():\n", + " grid = product(\n", + " l2_val,\n", + " [preprocessing.StandardScaler, preprocessing.MaxAbsScaler, preprocessing.MinMaxScaler, preprocessing.RobustScaler],\n", + " optimz\n", + " )\n", + " \n", + " return [generate_pipeline(l2=l2, scaler=scaler, optimizer=optimizer) for (l2, scaler, optimizer) in grid]" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "def generate_pipeline(lr=0.2, l2=0, scaler=None, optimizer=None):\n", + " if scaler is None:\n", + " scaler = preprocessing.MinMaxScaler()\n", + " if optimizer is None:\n", + " optimizer = optim.SGD\n", + "\n", + " pipeline = compose.Pipeline(\n", + " scaler,\n", + " linear_model.LinearRegression(optimizer=optimizer(), l2=l2)\n", + " )\n", + " \n", + " return pipeline" + ] + }, + { + "cell_type": "raw", + "metadata": {}, + "source": [ + "from river import datasets\n", + "\n", + "dataset = datasets.Bananas()" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "50000it [20:50, 40.00it/s]\n" + ] + } + ], + "source": [ + "mae = metrics.MSE()\n", + "take_N = 50000\n", + "\n", + "f = test()\n", + "f = compute_reward\n", + "default_par = dict(compute_reward=f,\n", + " metric=mae, \n", + " verbose=False,\n", + " save_rewards=True)\n", + "\n", + "bandits = {\n", + " \"epsilon\" : EpsilonGreedyBandit(models=get_models(), epsilon=0.1, reduce_epsilon=None, **default_par),\n", + " \"ucb\" : UCBBandit(models=get_models(), delta=0.5, **default_par),\n", + " \"random\" : RandomBandit(models=get_models(), **default_par),\n", + " #\"exp3\" : Exp3Bandit(models=get_models(), gamma=0.1, **default_par)\n", + "}\n", + "\n", + "\n", + "bandit_oracle = OracleBandit(models=get_models(), **default_par)\n", + "\n", + "print_every = N // 10\n", + "\n", + "gen = gen_stream(dataset, take=take_N)\n", + "#gen = dataset.take(take_N)\n", + "\n", + "for i, (x, y) in tqdm.tqdm(enumerate(gen)):\n", + " \n", + " for bandit in bandits.values():\n", + " bandit.learn_one(x=x, y=y)\n", + " \n", + " bandit_oracle.learn_one(x=x, y=y)\n", + " \n", + " if i >= 2500:\n", + " pass#break\n", + " \n", + " \n", + "#print(bandit.percentage_pulled)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Inspecting oracle results" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "cumsum_final = pd.Series(np.array(bandit_oracle.rewards).cumsum(axis=0)[-1,:])\n", + "(cumsum_final - cumsum_final.mean()).plot(kind=\"bar\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Comparing results between bandits" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "df_rewards = pd.DataFrame({label: bandit.rewards for (label, bandit) in bandits.items()})\n", + "df_rewards[\"oracle\"] = bandit_oracle.max_rewards\n", + "\n", + "sns.displot(df_rewards, kde=True)\n", + "\n", + "(df_rewards\n", + " .cumsum()\n", + " .plot(color=[\"red\", \"blue\", 'green', \"cyan\" ,\"magenta\"])\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 190, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 190, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "pd.DataFrame({\"original\": {feature_name:beta \n", + " for (feature_name, beta) \n", + " in zip(dataset.feature_names, dataset.beta)},\n", + " \"learned\": bandits[\"ucb\"].best_model[\"LinearRegression\"].weights}).plot(kind=\"bar\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "river-env", + "language": "python", + "name": "river-env" + }, + "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.7.7" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/river/expert/__init__.py b/river/expert/__init__.py index 9ad4e87653..cc777fc485 100644 --- a/river/expert/__init__.py +++ b/river/expert/__init__.py @@ -16,6 +16,13 @@ """ +from .bandit import ( + EpsilonGreedyBandit, + Exp3Bandit, + OracleBandit, + UCBBandit, + RandomBandit +) from .ewa import EWARegressor from .sh import SuccessiveHalvingClassifier from .sh import SuccessiveHalvingRegressor @@ -23,8 +30,13 @@ __all__ = [ + 'EpsilonGreedyBandit', + 'Exp3Bandit', 'EWARegressor', + 'OracleBandit', + 'RandomBandit', 'SuccessiveHalvingClassifier', 'SuccessiveHalvingRegressor', - 'StackingClassifier' + 'StackingClassifier', + 'UCBBandit' ] diff --git a/river/expert/bandit.py b/river/expert/bandit.py new file mode 100644 index 0000000000..77992b78a2 --- /dev/null +++ b/river/expert/bandit.py @@ -0,0 +1,263 @@ +import abc + +import numpy as np + +from river import metrics + + +__all__ = [ + 'EpsilonGreedyBandit', + 'UCBBandit', + 'RandomBandit', + 'OracleBandit', + 'Exp3Bandit' +] + +# TODO : +# type annotation in __init__ +# loss-based reward ('compute_reward') +# tests for classification +# tests on real datasets + + +class Bandit(metaclass=abc.ABCMeta): + """Abstract class for bandit. + + References + ---------- + [^1] [Python code from Toulouse univ](https://www.math.univ-toulouse.fr/~jlouedec/demoBandits.html) + [^2] [Slivkins, A. Introduction to Multi-Armed Bandits](https://arxiv.org/pdf/1904.07272.pdf) + """ + + def __init__(self, models, compute_reward, metric: metrics.Metric = None, + verbose=False, save_rewards=False): + if len(models) <= 1: + raise ValueError(f"You supply {len(models)} models. At least 2 models should be supplied.") + + self.compute_reward = compute_reward + self.metric = metric + self.verbose = verbose + self.models = models + self.save_rewards = save_rewards + if save_rewards: + self.rewards = [] + + self._n_arms = len(models) + self._Q = np.zeros(self._n_arms, dtype=np.float) + self._N = np.ones(self._n_arms, dtype=np.int) + + @abc.abstractmethod + def _pull_arm(self): + pass + + @abc.abstractmethod + def _update_arm(self, arm, reward): + pass + + @property + def _best_model_idx(self): + return np.argmax(self._Q) + + @property + def best_model(self): + return self.models[self._best_model_idx] + + def print_percentage_pulled(self): + percentages = self._N / sum(self._N) + for i, pct in enumerate(percentages): + print(f"Model {i}: {round(pct*100, 2)}% of the time") + + def predict_one(self, x): + best_arm = self._pull_arm() + y_pred = self.models[best_arm].predict_one(x) + + return y_pred + + def learn_one(self, x, y): + best_arm = self._pull_arm() + best_model = self.models[best_arm] + y_pred = best_model.predict_one(x) + + best_model.learn_one(x=x, y=y) + + if self.verbose: + print( + '\t'.join(( + f'best {self._best_model_idx}', + )) + ) + print("y_pred:", y_pred, ", y_true:", y) + + reward = self.compute_reward(y_pred=y_pred, y_true=y) + + if self.metric: + self.metric.update(y_pred=y_pred, y_true=y) + + if self.save_rewards: + self.rewards += [reward] + + self._update_arm(best_arm, reward) + + return self + + +class EpsilonGreedyBandit(Bandit): + """Epsilon-greedy bandit implementation + + Parameters + ---------- + models + The models to compare. + metric + Metric used for comparing models with. + epsilon + Exploration parameter (default : 0.1). + reduce_epsilon + Factor applied to reduce epsilon at each time-step (default : 0.99). + + + Examples + -------- + TODO + + References + ---------- + [^1]: [Sutton, R. S., & Barto, A. G. (2018). Reinforcement learning: An introduction. MIT press.](http://incompleteideas.net/book/RLbook2020.pdf) + """ + + def __init__(self, epsilon=0.1, reduce_epsilon=0.99, **kwargs): + super().__init__(**kwargs) + self.epsilon = epsilon + self.reduce_epsilon = reduce_epsilon + + def _pull_arm(self): + if np.random.rand() > self.epsilon: + best_arm = np.argmax(self._Q) + else: + best_arm = np.random.choice(self._n_arms) + + return best_arm + + def _update_arm(self, arm, reward): + if self.reduce_epsilon: + self.epsilon *= self.reduce_epsilon + self._N[arm] += 1 + self._Q[arm] += (1.0 / self._N[arm]) * (reward - self._Q[arm]) + + +class UCBBandit(Bandit): + """Upper Confidence Bound bandit. + + References + ---------- + [^1]: [Auer, P., Cesa-Bianchi, N., & Fischer, P. (2002). Finite-time analysis of the multiarmed bandit problem. Machine learning, 47(2-3), 235-256.](https://link.springer.com/content/pdf/10.1023/A:1013689704352.pdf) + """ + + def __init__(self, delta, **kwargs): + super().__init__(**kwargs) + self._t = 1 + self.delta = delta + + def _pull_arm(self): + #upper_bound = self._Q + np.sqrt(2*np.log(self._t)/self._N) + upper_bound = self._Q + np.sqrt(2*np.log(1/self.delta)/self._N) + best_arm = np.argmax(upper_bound) + return best_arm + + def _update_arm(self, arm, reward): + self._N[arm] += 1 + self._Q[arm] += (1.0 / self._N[arm]) * (reward - self._Q[arm]) + self._t += 1 + + +class Exp3Bandit(Bandit): + """Exp3 implementation from Lattimore and Szepesvári. The algorithm makes the hypothesis that the reward is in [0, 1] + + References + ---------- + [^1]: [Lattimore, T., & Szepesvári, C. (2020). Bandit algorithms. Cambridge University Press.](https://tor-lattimore.com/downloads/book/book.pdf) + """ + + def __init__(self, gamma=0.5, **kwargs): + super().__init__(**kwargs) + self._p = np.ones(self._n_arms, dtype=np.float) + self._s = np.zeros(self._n_arms, dtype=np.float) + self.gamma = gamma + + def _make_distr(self): + numerator = np.exp(self.gamma * self._s) + return numerator / np.sum(numerator) + + def _pull_arm(self): + self._p = self._make_distr() + best_arm = np.random.choice(a=range(self._n_arms), size=1, p=self._p)[0] + return best_arm + + def _update_arm(self, arm, reward): + self._s += 1.0 + self._s[arm]-= (1.0 - reward)/self._p[arm] + + +class RandomBandit(Bandit): + """Bandit that does random selection and update of models. + It is just created for testing purpose""" + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + def _pull_arm(self): + random_arm = np.random.choice(len(self._N)) + return random_arm + + def _update_arm(self, arm, reward): + pass + + +class OracleBandit(Bandit): + """Oracle bandit that draws and updates every models. + The `predict_one` is the prediction that minimize the error for this time step. + The `update_one` update all the models available.""" + + def __init__(self, save_predictions=True, **kwargs): + super().__init__(**kwargs) + self.save_predictions = save_predictions + if save_predictions: + self.predictions = [] + + @property + def _best_model_idx(self): + cum_rewards = np.max(np.array(self.rewards), axis=0) + return np.argmax(cum_rewards) + + @property + def max_rewards(self): + return np.max(np.array(self.rewards), axis=1) + + def predict_one(self, x, y): + best_arm = self._pull_arm(x, y) + y_pred = self.models[best_arm].predict_one(x) + return y_pred + + def _pull_arm(self, x, y): + preds = [model.predict_one(x) for model in self.models] + losses = [np.abs(y_pred - y) for y_pred in preds] + best_arm = np.argmin(losses) + return best_arm + + def _update_arm(self, arm, reward): + pass + + def learn_one(self, x, y): + reward = [] + prediction = [] + for model in self.models: + y_pred = model.predict_one(x=x) + prediction += [y_pred] + r = self.compute_reward(y_pred=y_pred, y_true=y) + reward += [r] + model.learn_one(x=x, y=y) + + if self.save_predictions: + self.predictions += [prediction] + if self.save_rewards: + self.rewards += [reward] From 13154a60b67d3e906e04237a8afe248d86c7a5db Mon Sep 17 00:00:00 2001 From: Etienne Kintzler Date: Sun, 22 Nov 2020 20:03:16 +0100 Subject: [PATCH 02/14] improve docstring, rm class not in PR, clean some --- river/expert/__init__.py | 19 +-- river/expert/bandit.py | 361 ++++++++++++++++++++------------------- 2 files changed, 190 insertions(+), 190 deletions(-) diff --git a/river/expert/__init__.py b/river/expert/__init__.py index cc777fc485..c867ad3617 100644 --- a/river/expert/__init__.py +++ b/river/expert/__init__.py @@ -17,12 +17,10 @@ """ from .bandit import ( - EpsilonGreedyBandit, - Exp3Bandit, - OracleBandit, - UCBBandit, - RandomBandit + EpsilonGreedyRegressor, + UCBRegressor, ) + from .ewa import EWARegressor from .sh import SuccessiveHalvingClassifier from .sh import SuccessiveHalvingRegressor @@ -30,13 +28,10 @@ __all__ = [ - 'EpsilonGreedyBandit', - 'Exp3Bandit', - 'EWARegressor', - 'OracleBandit', - 'RandomBandit', + "EpsilonGreedyRegressor", + 'EWARegressor', 'SuccessiveHalvingClassifier', 'SuccessiveHalvingRegressor', 'StackingClassifier', - 'UCBBandit' -] + 'UCBRegressor', +] \ No newline at end of file diff --git a/river/expert/bandit.py b/river/expert/bandit.py index 77992b78a2..8665c21981 100644 --- a/river/expert/bandit.py +++ b/river/expert/bandit.py @@ -1,50 +1,53 @@ import abc +import copy +import typing import numpy as np +from river import base from river import metrics +from river import preprocessing __all__ = [ - 'EpsilonGreedyBandit', - 'UCBBandit', - 'RandomBandit', - 'OracleBandit', - 'Exp3Bandit' + "EpsilonGreedyRegressor", + 'UCBRegressor', ] -# TODO : -# type annotation in __init__ -# loss-based reward ('compute_reward') -# tests for classification -# tests on real datasets +# TODO: +# Docstring +# Determine which object to store (rewards/percentages pulled/loss?) +class Bandit(base.EnsembleMixin): + def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transformer, + print_every=None, save_metric_values=False, save_percentage_pulled=False): -class Bandit(metaclass=abc.ABCMeta): - """Abstract class for bandit. - - References - ---------- - [^1] [Python code from Toulouse univ](https://www.math.univ-toulouse.fr/~jlouedec/demoBandits.html) - [^2] [Slivkins, A. Introduction to Multi-Armed Bandits](https://arxiv.org/pdf/1904.07272.pdf) - """ - - def __init__(self, models, compute_reward, metric: metrics.Metric = None, - verbose=False, save_rewards=False): if len(models) <= 1: raise ValueError(f"You supply {len(models)} models. At least 2 models should be supplied.") - - self.compute_reward = compute_reward - self.metric = metric - self.verbose = verbose - self.models = models - self.save_rewards = save_rewards - if save_rewards: - self.rewards = [] + # Check that the model and the metric are in accordance + for model in models: + if not metric.works_with(model): + raise ValueError(f"{metric.__class__.__name__} metric can't be used to evaluate a " + + f'{model.__class__.__name__}') + super().__init__(models) + self.reward_scaler = copy.deepcopy(reward_scaler) + self.metric = copy.deepcopy(metric) + self.print_every = print_every + + self.save_metric_values = save_metric_values + if save_metric_values: + self.metric_values: typing.List = [] + + self.save_percentage_pulled = save_percentage_pulled + if save_percentage_pulled: + self.store_percentage_pulled: typing.List = [] + + # Initializing bandits internals self._n_arms = len(models) - self._Q = np.zeros(self._n_arms, dtype=np.float) - self._N = np.ones(self._n_arms, dtype=np.int) + self._n_iter = 0 # number of times learn_one is called + self._N = np.zeros(self._n_arms, dtype=np.int) + self._average_reward = np.zeros(self._n_arms, dtype=np.float) @abc.abstractmethod def _pull_arm(self): @@ -54,56 +57,123 @@ def _pull_arm(self): def _update_arm(self, arm, reward): pass + @abc.abstractmethod + def _pred_func(self, model): + pass + @property def _best_model_idx(self): - return np.argmax(self._Q) + # average reward instead of cumulated (otherwise favors arms which are pulled often) + return np.argmax(self._average_reward) @property def best_model(self): - return self.models[self._best_model_idx] + return self[self._best_model_idx] - def print_percentage_pulled(self): + @property + def percentage_pulled(self): percentages = self._N / sum(self._N) - for i, pct in enumerate(percentages): - print(f"Model {i}: {round(pct*100, 2)}% of the time") + return percentages def predict_one(self, x): best_arm = self._pull_arm() - y_pred = self.models[best_arm].predict_one(x) - + y_pred = self._pred_func(self[best_arm])(x) return y_pred def learn_one(self, x, y): - best_arm = self._pull_arm() - best_model = self.models[best_arm] - y_pred = best_model.predict_one(x) + chosen_arm = self._pull_arm() + chosen_model = self[chosen_arm] + + y_pred = chosen_model.predict_one(x) + self.metric.update(y_pred=y_pred, y_true=y) + chosen_model.learn_one(x=x, y=y) + + # Update bandit internals (common to all bandit) + reward = self._compute_scaled_reward(y_pred=y_pred, y_true=y) + self._n_iter += 1 + self._N[chosen_arm] += 1 + self._average_reward[chosen_arm] += (1.0 / self._N[chosen_arm]) * \ + (reward - self._average_reward[chosen_arm]) + + # Specific update of the arm for certain bandit class + self._update_arm(chosen_arm, reward) + + if self.print_every: + if (self._n_iter % self.print_every) == 0: + self._print_info() + + if self.save_percentage_pulled: + self.store_percentage_pulled += [self.percentage_pulled] - best_model.learn_one(x=x, y=y) + if self.save_metric_values: + self.metric_values += [self.metric._eval(y_pred, y)] - if self.verbose: - print( - '\t'.join(( - f'best {self._best_model_idx}', - )) - ) - print("y_pred:", y_pred, ", y_true:", y) + return self - reward = self.compute_reward(y_pred=y_pred, y_true=y) + def add_models(self, new_models): + if not isinstance(new_models, list): + raise TypeError("Argument `new_models` must be of a list") + + length_new_models = len(new_models) + # Careful, not validation of the model is done here (contrary to __init__) + self.models += new_models + self._n_arms += length_new_models + self._N = np.concatenate([self._N, np.zeros(length_new_models, dtype=np.int)]) + self._average_reward = np.concatenate([self._average_reward, np.zeros(length_new_models, dtype=np.float)]) + + def _compute_scaled_reward(self, y_pred, y_true, update_scaler=True): + metric_value = self.metric._eval(y_pred, y_true) + metric_to_reward_dict = { + "metric": metric_value if self.metric.bigger_is_better else (-1) * metric_value + } + if update_scaler: + self.reward_scaler.learn_one(metric_to_reward_dict) + reward = self.reward_scaler.transform_one(metric_to_reward_dict)["metric"] + return reward + + def _print_info(self): + print( + str(self), + str(self.metric), + "Best model id: " + str(self._best_model_idx), + sep="\n\t" + ) - if self.metric: - self.metric.update(y_pred=y_pred, y_true=y) - if self.save_rewards: - self.rewards += [reward] +class EpsilonGreedyBandit(Bandit): + def __init__(self, epsilon=0.1, epsilon_decay=None, **kwargs): + super().__init__(**kwargs) + self.epsilon = epsilon + self.epsilon_decay = epsilon_decay + if epsilon_decay: + self._starting_epsilon = epsilon + if not self.reward_scaler: + self.reward_scaler = preprocessing.StandardScaler() - self._update_arm(best_arm, reward) + def _pull_arm(self): + if np.random.rand() > self.epsilon: + chosen_arm = np.argmax(self._average_reward) + else: + chosen_arm = np.random.choice(self._n_arms) - return self + return chosen_arm + def _update_arm(self, arm, reward): + # The arm internals are already updated in the `learn_one` phase of class `Bandit`. + if self.epsilon_decay: + self.epsilon = self._starting_epsilon*np.exp(-self._n_iter*self.epsilon_decay) + + +class EpsilonGreedyRegressor(EpsilonGreedyBandit, base.Regressor): + """Epsilon-greedy bandit algorithm for regression. + + This bandit selects the best arm (defined as the one with the highest average reward) with + probability $(1 - \epsilon)$ and draws a random arm with probability $\epsilon$. It is also + called Follow-The-Leader (FTL) algorithm. + + For this bandit, reward are supposed to be 1-subgaussian, hence the use of the StandardScaler + and MaxAbsScaler as `reward_scaler`. -class EpsilonGreedyBandit(Bandit): - """Epsilon-greedy bandit implementation - Parameters ---------- models @@ -112,152 +182,87 @@ class EpsilonGreedyBandit(Bandit): Metric used for comparing models with. epsilon Exploration parameter (default : 0.1). - reduce_epsilon - Factor applied to reduce epsilon at each time-step (default : 0.99). Examples -------- - TODO + >>> from river import linear_model + >>> from river import expert + >>> from river import preprocessing + >>> from river import metrics + + + TODO: finish ex - References + References ---------- [^1]: [Sutton, R. S., & Barto, A. G. (2018). Reinforcement learning: An introduction. MIT press.](http://incompleteideas.net/book/RLbook2020.pdf) + [^2]: [Rivasplata, O. (2012). Subgaussian random variables: An expository note. Internet publication, PDF.]: (https://sites.ualberta.ca/~omarr/publications/subgaussians.pdf) + [^3]: [Lattimore, T., & Szepesvári, C. (2020). Bandit algorithms. Cambridge University Press.](https://tor-lattimore.com/downloads/book/book.pdf) """ - def __init__(self, epsilon=0.1, reduce_epsilon=0.99, **kwargs): - super().__init__(**kwargs) - self.epsilon = epsilon - self.reduce_epsilon = reduce_epsilon - - def _pull_arm(self): - if np.random.rand() > self.epsilon: - best_arm = np.argmax(self._Q) - else: - best_arm = np.random.choice(self._n_arms) - - return best_arm - - def _update_arm(self, arm, reward): - if self.reduce_epsilon: - self.epsilon *= self.reduce_epsilon - self._N[arm] += 1 - self._Q[arm] += (1.0 / self._N[arm]) * (reward - self._Q[arm]) + def _pred_func(self, model): + return model.predict_one class UCBBandit(Bandit): - """Upper Confidence Bound bandit. - - References - ---------- - [^1]: [Auer, P., Cesa-Bianchi, N., & Fischer, P. (2002). Finite-time analysis of the multiarmed bandit problem. Machine learning, 47(2-3), 235-256.](https://link.springer.com/content/pdf/10.1023/A:1013689704352.pdf) - """ - - def __init__(self, delta, **kwargs): + def __init__(self, delta=None, explore_each_arm=1, **kwargs): super().__init__(**kwargs) - self._t = 1 + if delta is not None and (delta >= 1 or delta <= 0): + raise ValueError("The parameter delta should be comprised in ]0, 1[ (or set to None)") self.delta = delta + self.explore_each_arm = explore_each_arm - def _pull_arm(self): - #upper_bound = self._Q + np.sqrt(2*np.log(self._t)/self._N) - upper_bound = self._Q + np.sqrt(2*np.log(1/self.delta)/self._N) - best_arm = np.argmax(upper_bound) - return best_arm - - def _update_arm(self, arm, reward): - self._N[arm] += 1 - self._Q[arm] += (1.0 / self._N[arm]) * (reward - self._Q[arm]) - self._t += 1 - - -class Exp3Bandit(Bandit): - """Exp3 implementation from Lattimore and Szepesvári. The algorithm makes the hypothesis that the reward is in [0, 1] - - References - ---------- - [^1]: [Lattimore, T., & Szepesvári, C. (2020). Bandit algorithms. Cambridge University Press.](https://tor-lattimore.com/downloads/book/book.pdf) - """ - - def __init__(self, gamma=0.5, **kwargs): - super().__init__(**kwargs) - self._p = np.ones(self._n_arms, dtype=np.float) - self._s = np.zeros(self._n_arms, dtype=np.float) - self.gamma = gamma - - def _make_distr(self): - numerator = np.exp(self.gamma * self._s) - return numerator / np.sum(numerator) + if not self.reward_scaler: + self.reward_scaler = preprocessing.StandardScaler() def _pull_arm(self): - self._p = self._make_distr() - best_arm = np.random.choice(a=range(self._n_arms), size=1, p=self._p)[0] - return best_arm - - def _update_arm(self, arm, reward): - self._s += 1.0 - self._s[arm]-= (1.0 - reward)/self._p[arm] - - -class RandomBandit(Bandit): - """Bandit that does random selection and update of models. - It is just created for testing purpose""" - - def __init__(self, **kwargs): - super().__init__(**kwargs) + not_pulled_enough = self._N <= self.explore_each_arm + if any(not_pulled_enough): # Explore all arms pulled less than `explore_each_arm` times + never_pulled_arm = np.where(not_pulled_enough)[0] #[0] because returned a tuple (array(),) even when input is 1D array + chosen_arm = np.random.choice(never_pulled_arm) + else: + if self.delta: + exploration_bonus = np.sqrt(2 * np.log(1/self.delta) / self._N) + else: + exploration_bonus = np.sqrt(2 * np.log(self._n_iter) / self._N) + upper_bound = self._average_reward + exploration_bonus + chosen_arm = np.argmax(upper_bound) - def _pull_arm(self): - random_arm = np.random.choice(len(self._N)) - return random_arm + return chosen_arm def _update_arm(self, arm, reward): + # The arm internals are already updated in the `learn_one` phase of class `Bandit`. pass -class OracleBandit(Bandit): - """Oracle bandit that draws and updates every models. - The `predict_one` is the prediction that minimize the error for this time step. - The `update_one` update all the models available.""" +class UCBRegressor(UCBBandit, base.Regressor): + """Upper Confidence Bound bandit for regression. - def __init__(self, save_predictions=True, **kwargs): - super().__init__(**kwargs) - self.save_predictions = save_predictions - if save_predictions: - self.predictions = [] + The class offers 2 implementations of UCB: + - UCB1 from [^1], when the parameter delta has value None + - UCB(delta) from [^2], when the parameter delta is in (0, 1) - @property - def _best_model_idx(self): - cum_rewards = np.max(np.array(self.rewards), axis=0) - return np.argmax(cum_rewards) + For this bandit, rewards are supposed to be 1-subgaussian (see Lattimore and Szepesvári, + chapter 6, p. 91) hence the use of the `StandardScaler` and `MaxAbsScaler` as `reward_scaler`. - @property - def max_rewards(self): - return np.max(np.array(self.rewards), axis=1) + Parameters + ---------- + models + The models to compare. + metric + Metric used for comparing models with. + delta + For UCB(delta) implementation. Lower value means more exploration. - def predict_one(self, x, y): - best_arm = self._pull_arm(x, y) - y_pred = self.models[best_arm].predict_one(x) - return y_pred - def _pull_arm(self, x, y): - preds = [model.predict_one(x) for model in self.models] - losses = [np.abs(y_pred - y) for y_pred in preds] - best_arm = np.argmin(losses) - return best_arm + References + ---------- + [^1]: [Auer, P., Cesa-Bianchi, N., & Fischer, P. (2002). Finite-time analysis of the multiarmed bandit problem. Machine learning, 47(2-3), 235-256.](https://link.springer.com/content/pdf/10.1023/A:1013689704352.pdf) + [^2]: [Lattimore, T., & Szepesvári, C. (2020). Bandit algorithms. Cambridge University Press.](https://tor-lattimore.com/downloads/book/book.pdf) + [^3]: [Rivasplata, O. (2012). Subgaussian random variables: An expository note. Internet publication, PDF.]: (https://sites.ualberta.ca/~omarr/publications/subgaussians.pdf) + """ - def _update_arm(self, arm, reward): - pass + def _pred_func(self, model): + return model.predict_one - def learn_one(self, x, y): - reward = [] - prediction = [] - for model in self.models: - y_pred = model.predict_one(x=x) - prediction += [y_pred] - r = self.compute_reward(y_pred=y_pred, y_true=y) - reward += [r] - model.learn_one(x=x, y=y) - - if self.save_predictions: - self.predictions += [prediction] - if self.save_rewards: - self.rewards += [reward] From b0fefc6f33fdb13ec4bcfab4f44a960dde8dc135 Mon Sep 17 00:00:00 2001 From: Etienne Kintzler Date: Sun, 22 Nov 2020 20:16:14 +0100 Subject: [PATCH 03/14] delete nb from pr, clean some --- benchmarks/Bandits_for_online_learning.ipynb | 469 ------------------- river/expert/__init__.py | 4 +- river/expert/bandit.py | 7 +- 3 files changed, 6 insertions(+), 474 deletions(-) delete mode 100644 benchmarks/Bandits_for_online_learning.ipynb diff --git a/benchmarks/Bandits_for_online_learning.ipynb b/benchmarks/Bandits_for_online_learning.ipynb deleted file mode 100644 index 86e11f92ec..0000000000 --- a/benchmarks/Bandits_for_online_learning.ipynb +++ /dev/null @@ -1,469 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext autoreload\n", - "%autoreload 2" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from collections import namedtuple\n", - "import itertools \n", - "\n", - "import numpy as np\n", - "import pandas as pd\n", - "import matplotlib.pyplot as plt\n", - "import seaborn as sns\n", - "import tqdm\n", - "\n", - "from river import (\n", - " optim,\n", - " datasets,\n", - " preprocessing,\n", - " linear_model,\n", - " metrics,\n", - " compose\n", - " )\n", - "from river.stream import iter_sklearn_dataset\n", - "from river.expert import (\n", - " EpsilonGreedyBandit,\n", - " UCBBandit,\n", - " Exp3Bandit,\n", - " RandomBandit,\n", - " OracleBandit\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "\n", - "def gen_xy_numpy(N=1000, p=1, intercept=0.0, seed=None, drift=False):\n", - " N = int(N)\n", - " \n", - " if seed:\n", - " np.random.seed(seed)\n", - "\n", - " beta = np.random.normal(size=p, scale=2)\n", - "\n", - " x_arr = np.random.uniform(size=(N, p))\n", - " noise = np.random.normal(size=N, scale=0.15)\n", - " xb = intercept + np.sum(x_arr*beta, axis=1) \n", - " \n", - " if drift:\n", - " tier = N // 3\n", - " xb[tier:(2 * tier)] *= -1\n", - " xb[(2 * tier):] *= -1\n", - " beta *= -1\n", - " \n", - " y_arr = xb + noise\n", - "\n", - " return x_arr, y_arr, beta\n", - "\n", - "\n", - "Dataset = namedtuple(\"dat\", [\"target\", \"data\", \"feature_names\", \"beta\"])\n", - "\n", - "\n", - "def gen_dataset(**kwargs):\n", - " x_arr, y_arr, beta = gen_xy_numpy(**kwargs)\n", - " dataset = Dataset(y_arr, x_arr, [\"x{}\".format(i) for i in range(p)], beta)\n", - " return dataset\n", - "\n", - "\n", - "def gen_stream(dataset=None, take=None):\n", - " if dataset is None:\n", - " dataset = gen_dataset()\n", - " \n", - " gen = iter_sklearn_dataset(dataset)\n", - " \n", - " if take:\n", - " return itertools.islice(gen, take)\n", - " else:\n", - " return gen\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Studying loss behavior" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Paper on rewards scaling : \n", - "\n", - " - [Learning values across many orders of magnitude](https://arxiv.org/pdf/1602.07714.pdf)\n", - " \n", - " - [Stack message](https://datascience.stackexchange.com/questions/20098/why-do-we-normalize-the-discounted-rewards-when-doing-policy-gradient-reinforcem)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "def test():\n", - " \n", - " sc = preprocessing.MinMaxScaler()\n", - " \n", - " def compute_reward(y_pred, y_true, power=2):\n", - " loss = np.power(np.abs(y_pred - y_true), power)\n", - " loss_d = dict(l=loss)\n", - " loss = sc.learn_one(loss_d).transform_one(loss_d)[\"l\"]\n", - " return (1 / (1+ loss))\n", - " return 1 - loss\n", - " \n", - " return compute_reward" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "def compute_reward(y_pred, y_true, power=2):\n", - " loss = np.power(np.abs(y_pred - y_true), power)\n", - " return 1/ (1 + np.sqrt(loss))\n", - "\n", - "limit = 30\n", - "round_factor = 3\n", - "x = np.arange(-limit, limit, 0.25)\n", - "y = np.arange(-limit, limit, 0.25)\n", - "xx, yy = np.meshgrid(x, y, sparse=True)\n", - "\n", - "f = test()\n", - "z = compute_reward(xx, yy, power=1)\n", - "z_df = (pd.DataFrame(z)\n", - " .set_index(np.round(x, round_factor))\n", - " .rename(columns={\n", - " i:val for (i, val) in enumerate(np.round(y, round_factor))\n", - " }))\n", - "\n", - "f, ax = plt.subplots(figsize=(9, 6))\n", - "ax = sns.heatmap(z_df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Dataset generation" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "N = 1e5\n", - "p = 20\n", - "dataset = gen_dataset(p=p, N=N, intercept=.5, drift=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Training and bandits" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "l2_val=[1e-6, 1e-4, 1e-2, 1e-1, 1e-0, 2, 3]\n", - "optimz = [optim.SGD, optim.Adam]" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "from itertools import product\n", - "\n", - "def get_models():\n", - " grid = product(\n", - " l2_val,\n", - " [preprocessing.StandardScaler, preprocessing.MaxAbsScaler, preprocessing.MinMaxScaler, preprocessing.RobustScaler],\n", - " optimz\n", - " )\n", - " \n", - " return [generate_pipeline(l2=l2, scaler=scaler, optimizer=optimizer) for (l2, scaler, optimizer) in grid]" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [], - "source": [ - "def generate_pipeline(lr=0.2, l2=0, scaler=None, optimizer=None):\n", - " if scaler is None:\n", - " scaler = preprocessing.MinMaxScaler()\n", - " if optimizer is None:\n", - " optimizer = optim.SGD\n", - "\n", - " pipeline = compose.Pipeline(\n", - " scaler,\n", - " linear_model.LinearRegression(optimizer=optimizer(), l2=l2)\n", - " )\n", - " \n", - " return pipeline" - ] - }, - { - "cell_type": "raw", - "metadata": {}, - "source": [ - "from river import datasets\n", - "\n", - "dataset = datasets.Bananas()" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "50000it [20:50, 40.00it/s]\n" - ] - } - ], - "source": [ - "mae = metrics.MSE()\n", - "take_N = 50000\n", - "\n", - "f = test()\n", - "f = compute_reward\n", - "default_par = dict(compute_reward=f,\n", - " metric=mae, \n", - " verbose=False,\n", - " save_rewards=True)\n", - "\n", - "bandits = {\n", - " \"epsilon\" : EpsilonGreedyBandit(models=get_models(), epsilon=0.1, reduce_epsilon=None, **default_par),\n", - " \"ucb\" : UCBBandit(models=get_models(), delta=0.5, **default_par),\n", - " \"random\" : RandomBandit(models=get_models(), **default_par),\n", - " #\"exp3\" : Exp3Bandit(models=get_models(), gamma=0.1, **default_par)\n", - "}\n", - "\n", - "\n", - "bandit_oracle = OracleBandit(models=get_models(), **default_par)\n", - "\n", - "print_every = N // 10\n", - "\n", - "gen = gen_stream(dataset, take=take_N)\n", - "#gen = dataset.take(take_N)\n", - "\n", - "for i, (x, y) in tqdm.tqdm(enumerate(gen)):\n", - " \n", - " for bandit in bandits.values():\n", - " bandit.learn_one(x=x, y=y)\n", - " \n", - " bandit_oracle.learn_one(x=x, y=y)\n", - " \n", - " if i >= 2500:\n", - " pass#break\n", - " \n", - " \n", - "#print(bandit.percentage_pulled)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Inspecting oracle results" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "cumsum_final = pd.Series(np.array(bandit_oracle.rewards).cumsum(axis=0)[-1,:])\n", - "(cumsum_final - cumsum_final.mean()).plot(kind=\"bar\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Comparing results between bandits" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAbEAAAFgCAYAAAA1skc7AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Il7ecAAAACXBIWXMAAAsTAAALEwEAmpwYAAA/NElEQVR4nO3deXwlZ33n+8+vzqJztLXU6n1zL27vhgYbGwgwEAJxGAZIJkMgJDgZBk+GkDtcJjOBYe4ly+VekglkwkyGxEk8wA1gSMDgEINjHC+Abez21t1uu92r1K1eJLV26axVv/njlLqPm17ktqSjkr7v1+u8Tp2n6lQ9Jdn91fPUU0+ZuyMiIpJEQaMrICIicrEUYiIiklgKMRERSSyFmIiIJJZCTEREEivd6ArMtZtuusm/973vNboaIrJwWaMrsJgsupbYwMBAo6sgIiIzZNGFmIiILBwKMRERSSyFmIiIJJZCTEREEmvWQszMbjOzPjPbVVf2NTN7Kn4dMrOn4vKNZlaoW/fndd+5zsx2mtk+M/ucmVlcvtTM7jGzvfF752ydi4iIzE+z2RL7AnBTfYG7/5K7b3P3bcA3gG/Wrd4/tc7df6Ou/PPAB4Gt8Wtqnx8D7nX3rcC98WcREVlEZi3E3P1BYPBs6+LW1LuBr55vH2a2Gmh390e8Nt3+l4B3xavfCXwxXv5iXbmIiCwSjbom9nrghLvvrSvbZGZPmtkDZvb6uGwtcKRumyNxGcBKdz8WLx8HVp7rYGZ2i5ltN7Pt/f39M3QKIiLSaI0KsffywlbYMWCDu78C+CjwFTNrn+7O4lbaOR+M5u63uvv17n798uXLL7bOIiIyz8z5tFNmlgZ+AbhuqszdS0ApXn7czPYDlwG9wLq6r6+LywBOmNlqdz8Wdzv2zUX9RURk/mhES+xngOfc/VQ3oZktN7NUvLyZ2gCOA3F34aiZvTq+jvZ+4Nvx1+4Ebo6Xb64rFxGRRWI2h9h/FXgYuNzMjpjZB+JV7+EnB3S8AdgRD7n/O+A33H1qUMiHgL8C9gH7ge/G5Z8G3mJme6kF46dn61xERGR+strlpMXj+uuv9+3btze6GiKycGkW+zm06B7FIiJyPmEY0tPTA8CGDRtIpVINrpGcj0JMRKROT08PO//bn9Y+fOTfs2nTpsZWSM5LISYicoY1nR2NroJMkyYAFhGRxFKIiYhIYinEREQksRRiIiKSWAoxERFJLIWYiIgklkJMREQSSyEmIiKJpRATEZHEUoiJiEhiKcRERCSxFGIiIpJYCjEREUkshZiIiCSWQkxERBJLISYiIomlEBMRkcRSiImISGIpxEREJLEUYiIiklgKMRERSSyFmIiIJJZCTEREEkshJiIiiaUQExGRxFKIiYhIYinEREQksRRiIiKSWAoxERFJLIWYiIgklkJMREQSSyEmIiKJpRATEZHEmrUQM7PbzKzPzHbVlf2umfWa2VPx62116z5uZvvMbI+Z/Wxd+U1x2T4z+1hd+SYz+3Fc/jUzy87WuYiIyPw0my2xLwA3naX8T9x9W/y6C8DMrgLeA1wdf+d/mlnKzFLAnwE/B1wFvDfeFuAP431dCgwBH5jFcxERkXlo1kLM3R8EBqe5+TuB29295O4HgX3ADfFrn7sfcPcycDvwTjMz4KeBv4u//0XgXTNZfxERmf8acU3sw2a2I+5u7IzL1gKH67Y5Epedq7wLGHb36hnlZ2Vmt5jZdjPb3t/fP1PnISIiDTbXIfZ5YAuwDTgGfGYuDurut7r79e5+/fLly+fikCIiMgfSc3kwdz8xtWxmfwl8J/7YC6yv23RdXMY5yk8CHWaWjltj9duLiMgiMactMTNbXffx54GpkYt3Au8xsyYz2wRsBR4FHgO2xiMRs9QGf9zp7g7cB/xi/P2bgW/PxTmIiMj8MWstMTP7KvBGYJmZHQE+CbzRzLYBDhwC/i2Auz9jZl8HdgNV4DfdPYz382HgbiAF3Obuz8SH+B3gdjP7f4Angb+erXMREZH5adZCzN3fe5bicwaNu38K+NRZyu8C7jpL+QFqoxdFRGSR0owdIiKSWAoxERFJLIWYiIgklkJMREQSSyEmIiKJpRATEZHEUoiJiEhiKcRERCSxFGIiIpJYCjEREUkshZiIiCSWQkxERBJLISYiIomlEBMRkcRSiImISGIpxEREJLEUYiIiklgKMRERSSyFmIiIJJZCTEREEkshJiIiiaUQExGRxFKIiYhIYinEREQksRRiIiKSWAoxERFJLIWYiIgklkJMREQSSyEmIiKJpRATEZHEUoiJiEhiKcRERCSxFGIiIpJYCjEREUkshZiIiCTWrIWYmd1mZn1mtquu7L+a2XNmtsPM7jCzjrh8o5kVzOyp+PXndd+5zsx2mtk+M/ucmVlcvtTM7jGzvfF752ydi4iIzE+z2RL7AnDTGWX3ANe4+8uA54GP163b7+7b4tdv1JV/HvggsDV+Te3zY8C97r4VuDf+LCIii8ishZi7PwgMnlH2j+5ejT8+Aqw73z7MbDXQ7u6PuLsDXwLeFa9+J/DFePmLdeUiIi9JcPw4mZ07G10NmYZGXhP718B36z5vMrMnzewBM3t9XLYWOFK3zZG4DGClux+Ll48DK2e1tiKyaKS7e8g8v7fR1ZBpSDfioGb2CaAKfDkuOgZscPeTZnYd8C0zu3q6+3N3NzM/z/FuAW4B2LBhw8VXXEQWBatUIIoaXQ2ZhjlviZnZrwFvB94XdxHi7iV3PxkvPw7sBy4Denlhl+O6uAzgRNzdONXt2HeuY7r7re5+vbtfv3z58hk+IxFZaKxSAT/n38Uyj8xpiJnZTcB/At7h7pN15cvNLBUvb6Y2gONA3F04amavjkclvh/4dvy1O4Gb4+Wb68pFRF6achmLIlxBNu/NWneimX0VeCOwzMyOAJ+kNhqxCbgnHin/SDwS8Q3A75tZBYiA33D3qUEhH6I20jFP7Rra1HW0TwNfN7MPAN3Au2frXERkcbFKpbYQho2tiFzQrIWYu7/3LMV/fY5tvwF84xzrtgPXnKX8JPDml1JHEZGzORVi1er5N5SG04wdIiJ13B3K5doHhdi8pxATEalXKmFT18Kq6k6c7xRiIiL1xsdPL4dqic13CjERkTo+MXF6Wd2J855CTESkXl2I6ZrY/KcQExGp4+P1IaZrYvOdQkxEpN5E3TWxaqVx9ZBpUYiJiNTxCbXEkkQhJiJSrz7ENDpx3lOIiYjUqb8mptGJ859CTESknkYnJopCTESkjr9gYIeuic13CjERkXrjE3gQ/9Oo0YnznkJMRKSOT0zgTU21D3oUy7ynEBMRqVcfYromNu8pxERE6nipBNlsbVkhNu8pxERE6lUqeDp+XrAGdsx7CjERkXrlMkyFmG52nvcUYiIi9epbYhWF2HynEBMRibk7VCqQUUssKRRiIiJTKrX7wjydqX3WNbF5TyEmIhKLyuXaQtyd6LrZed5TiImIxDwOMU+lcDO1xBJAISYiEpsKMVIBBIGuiSWAQkxEJOalUm0hiENMoxPnPYWYiEisvjsRM7XEEkAhJiISOzWwI0jVZrLXNbF5TyEmIhI785qY5k6c/xRiIiIxL8XdiVPXxBRi855CTEQk5pWpllgKAl0TSwKFmIhI7FR3YhDomlhCKMRERGIvHJ2o7sQkUIiJiMSiU/eJpXRNLCEUYiIisZ+csUPdifOdQkxEJObleBb7YGqIvSYAnu8UYiIisVPTTqVSeKAJgJNgVkPMzG4zsz4z21VXttTM7jGzvfF7Z1xuZvY5M9tnZjvM7JV137k53n6vmd1cV36dme2Mv/M5M7PZPB8RWdhODbHXfWKJMdstsS8AN51R9jHgXnffCtwbfwb4OWBr/LoF+DzUQg/4JHAjcAPwyangi7f5YN33zjyWiMi01Q+x1+jEZJjVEHP3B4HBM4rfCXwxXv4i8K668i95zSNAh5mtBn4WuMfdB919CLgHuCle1+7uj7i7A1+q25eIyIvm5TJkMrXJf/UolkRoxDWxle5+LF4+DqyMl9cCh+u2OxKXna/8yFnKf4KZ3WJm281se39//0s/AxFZkKJSGbJZgIbe7Gyp9BEz8xl7pdJHLnzUl1hns3eY2cfi5d81s9+e7WMCpOfiIOfi7m5mPgfHuRW4FeD666+f9eOJSDKdaokBBNa4CYCjcO0lv/Od35up3XX/4ds/OVP7Ohd3vxO4c7aPc6ZGtMROxF2BxO99cXkvsL5uu3Vx2fnK152lXETkorwwxBbXNTEz+xUze9TMnjKzvzCzlJmNm9mfmNkzZnavmS2Pt/0/zGx3PAjv9rjs18zsf5xlv9vM7JF42zvqBvPdb2Z/GB/zeTN7/cXUuxEhdicwNcLwZuDbdeXvj0cpvhoYibsd7wbeamad8cm/Fbg7XjdqZq+ORyW+v25fIiIvmpdKWH2ILZKbnc3sSuCXgJ9y921ACLwPaAG2u/vVwAPUBtlBbUDeK9z9ZcBvXGD3XwJ+J952Z90+ANLufgPwkTPKp21WuxPN7KvAG4FlZnaEWiU/DXzdzD4AdAPvjje/C3gbsA+YBH4dwN0HzewPgMfi7X7f3acGi3yI2gjIPPDd+CUiclG8UoZsHGIWQGXR3Oz8ZuA64LH4TqU8tV6yCPhavM3fAN+Ml3cAXzazbwHfOtdOzWwJ0OHuD8RFXwT+tm6Tqf09Dmy8mIrPaoi5+3vPserNZ9nWgd88x35uA247S/l24JqXUkcRkSlRXXeiL6KWGGDAF9394y8oNPu/zthuakzBPwfeAPwL4BNmdu1FHje+u5yQi8yjaXUnmtlPTadMRCTJznZNrPb39YJ3L/CLZrYCTk1KcQm1jPjFeJtfBn5oZgGw3t3vA34HWAK0nm2n7j4CDNVd7/pVat2SM2a6yfffgVdOo0xEJLG8VMYytSH2BPEEQNXq6WCbK0Gqd0ZHFAap8w56c/fdZvZfgH+MQ6pCrWdsArghXtdH7bpZCvibuKvQgM+5+/B5Jky6GfhzM2sGDhBfKpop5w0xM3sN8FpguZl9tG5VO7UTERFZMLxchlyu9iGodVR5tXp6sMdc1SOsrrvwVjN8TPevcfr6FwBmhrt/9Cybv+4s3/8CtTEKuPvv1pU/Bbz6LNu/sW55gFm6Jpal1kxMA2115aOcbmKKiCwIXi5DW+2fOq8LMZm/zhti8YiSB8zsC+7ePUd1EhFpCC+VTncdWhxii2eE4k9w97Ne65pPpntNrMnMbqXW3Dv1HXf/6dmolIhII0SV09NOTV0T84paYvPZdEPsb4E/B/6K2lBIEZEFx8uVF97sDKAHY85r0w2xqrt/flZrIiLSYF4unwqxU9fEFnF3YhJMd9qpvzezD5nZ6vj+gaXxc75ERBYML5VOz9ihgR2JMN2W2NRch/+xrsyBzTNbHRGRxqhWq3i5zGihQNTaSqqBIZZJ2ZFqdPZHS12MdEBvJfQZGbZvZm8Eftvd3z4T+3upphVi7r5ptisiItJIPQcPgjsDT+8g87JrWdrA0YnViLX+yfYZexSL/d7orD+KpVGmFWJm9v6zlbv7l2a2OiIiDRKHVXNzngoQtbeRfv/7Sa9Y0dh6zQEz2wh8x92viT//NrV7hP+G2qC+5dQG9f2r+CvtZvYPwKXAfcCH3D2a63rD9LsTX1W3nKM2ge8T1KbYFxFJvnIZAA9qkxF5Wxvp976HzMqV5/vWQvdl4NPufoeZ5aiNo1gP3ABcRe1JJN8DfgH4u0ZUcLrdib9V/9nMOoDbZ6NCIiINEbfEpkYlCm3AWne/A8Ddi1Cbigp41N0PxJ+/Sm0aqoaE2MX+tiYAXScTkQXDT4XYOSeyXciqvDAPchfY/syp/Rs21f90r4n9PacrmQKuBL4+W5USEZlzcXdiFCzKuc1PACvMrAsYB95OrZvwiJm9y92/ZWZNnJ74/QYz20StO/GXgFsbUWmY/jWxP65brgLd7n5kFuojItIYpdrzGT0V0Oi2WDqgdyZHFKYDLvQoloqZ/T7wKNALPBev+lXgL+J1FU4P7HgM+B+cHthxx0zV9cWa7jWxB8xsJacHeOydvSqJiDTA1MCOVKrhITZT93S9GO7+OeBzZ1l15hy5B6g91XlemO6Tnd9NLaH/FfBu4MdmpkexiMiC4aWp7kQN7EiS6XYnfgJ4lbv3AZjZcuD7NGg0iojIjCsVgVpLTJJjun9yBFMBFjv5Ir4rIjL/Le6BHYk13ZbY98zsbuCr8edfAu6anSqJiMy9qe5ET+nv8yQ5b4iZ2aXASnf/j2b2C9RuaAN4mNqd3CIiC0M5Hp2oa2KJcqGW2H8DPg7g7t8EvglgZtfG6/7FLNZNRGTuTA3s0DWxRLnQnxwr3X3nmYVx2cZZqZGISCOU5k9LzFJ2xMx8xl4pm9P7es3skJktm4tjXagl1nGedfkZrIeISEN5uVQLsHkQYkSsveYL18zYo1h2/dquad84bbXJEa1Rs9K/WBf6bW03sw+eWWhm/wZ4fHaqJCLSAKUyLNKuRDPbaGZ7zOxLwC7gr81su5k9Y2a/V7fdITP7PTN7wsx2mtkVcXmXmf1jvP1fwen7xc3so2a2K359pO54z5nZF8zseTP7spn9jJn9yMz2mtkN0637hVpiHwHuMLP3cTq0rgeywM9P9yAiIvNeubzY7xHbCtzs7o+Y2VJ3HzSzFHCvmb3M3XfE2w24+yvN7EPAbwP/Bvgk8EN3/30z++fABwDM7Drg14EbqQXbj83sAWCI2pRV/wr419SmsfplaoMH3wH8Z+Bd06n0eUPM3U8ArzWzNwHXxMX/4O7/NJ2di4gkhZeKi7YlFut290fi5Xeb2S3UMmI1tWeHTYXYN+P3x6k9Rwxq01D9AoC7/4OZDcXlrwPucPcJADP7JvB64E7g4NSYCzN7BrjX3d3MXtSYi+nOnXgftUkeRUQWpkXcnRibCppN1FpYr3L3ITP7Ai98NEspfg+Z/r3GZ1OqW47qPkcvZr/z4AqmiMg8oO7EKe3UAm0knvj956bxnQepdQdiZj8HdMblPwDeZWbNZtZC7TLUD2aysi8lRUVEFo5yaf60xAJ6X8yIwunsb7qbuvvTZvYktcexHAZ+NI2v/R7w1bhb8CGgJ97XE3FL7tF4u79y9yfNbOOLqP15KcRERAAvlvD0/Pgn0ef4USzufojT4x5w9187x3Yb65a3A2+Ml08Cbz3Hdz4LfHa6xztz3YWoO1FEBGoTAM+XlphMm0JMRATmV3eiTJtCTESE2iz2GtiRPHMeYmZ2uZk9VfcaNbOPmNnvmllvXfnb6r7zcTPbF99R/rN15TfFZfvM7GNzfS4isoCUy5BWiCXNnF/FdPc9wDaA+G7wXuAOand1/4m7/3H99mZ2FfAe4GpgDfB9M7ssXv1nwFuAI8BjZnanu++ei/MQkQWmVFJLLIEaPRTnzcB+d++uzTl5Vu8Ebnf3EnDQzPYBU/Nq7XP3AwBmdnu8rUJMRF4Ud6/NYq8QS5xGXxN7D6efFg3wYTPbYWa3mdnUzXJrqd2rMOVIXHau8p9gZrfEk1lu7+/vn7nai8iC4OXas8TmS4ilbWYfxZK2uX0UC4CZvdHMvjPbx2lYS8zMstQmevx4XPR54A8Aj98/Q21iyJfM3W8FbgW4/vrrfSb2KSILhxeLtfdUozunakJYu/vyK2bsUSxX7XnuJd04PZ8fz9LIltjPAU/Ekwzj7ifcPYx/SH/J6S7DXmB93ffWxWXnKhcReVGiOMTmS0usEc58ZMpZHs+y3sw+f45HtLzKzB4ys6fN7FEzaztj3y1xD9ujZvakmb1zpurdyD873ktdV6KZrXb3Y/HHn6f2Q4PabMdfMbPPUhvYsZXaFCYGbI0nq+yl1jX5y3NUdxFZQHyRh9jZHpkCPEDd41ni7T5x5iNaqE1P9TXgl9z9MTNrBwpnHOITwD+5+782sw7gUTP7/tTs9i9FQ0IsngjyLcC/rSv+IzPbRq078dDUOnd/xsy+Tm3ARhX4TXcP4/18GLgbSAG3ufszc3UOIrJwRMXaBOq+eIfYn+uRKfWPZ4GzP6LFgWPu/hiAu4/G+6jf/1uBd5jZb8efc8AG4NmXWvGGhFj8g+o6o+xXz7P9p4BPnaX8LuCuGa+giCwqXlrcLbHzONVSmsYjWs7HgH8Z32I1oxo9OlFEpOGiwtTAjkUbYtN5ZMq5HtGyB1htZq8CMLM2MzuzgXQ38FvxABHM7BUzVfH5MRRHRKSB5ltLLAW9L3VE4Zn7O9/6sz0yBRg6Y5uzPqLF3ctm9kvAfzezPLXrYT9zxiH+APhvwA4zC4CDwNtfyjlNUYiJyKI3NTrR02nwxt+FU/W5fRQLnP2RKZzxSJTzPKLlMeDVZxTfH79w9wIvHAMxY9SdKCKLnpdqAzvmS0tMpk8hJiKLnu4TSy6FmIgseq6BHYmlEBORRS+anKwtpDVMIGkUYiKy6EUTE7UAU0sscRRiIrLoRRMTkM83uhpyERRiIrLoKcSSSyEmIoteNDmBNSvEkkghJiKLXq0l1tzoashFUIiJyKIXTkxg6k5MJIWYiCx6uiaWXAoxEVn0oolJXRNLKIWYiCx6uiaWXAoxEVnU3F3diQmmEBORRc1LJQhDdScmlEJMRBa1aGKitqCWWCIpxERkUZsKMdM1sURSiInIoqaWWLIpxERkUTsVYromlkgKMRFZ1E53JyrEkkghJiKL2unuRF0TSyKFmIgsWmEYcqK7G4Bjw0NE7g2ukbxYCjERWbR6eno49r27AXj+777B2NhYg2skL5ZCTEQWtSWZDABdnR2NrYhcFIWYiCxu1Qqk0xDon8Mk0m9NRBY1q1SxuDUmyaMQE5FFzaoVhViCKcREZHGrVLFsttG1kIukEBORRc0qFYVYginERGRRs3KJIJdrdDXkIinERGRxK5UxhVhiKcREZNFyd6xcJmhqanRV5CI1LMTM7JCZ7TSzp8xse1y21MzuMbO98XtnXG5m9jkz22dmO8zslXX7uTnefq+Z3dyo8xGRBCqVsChSSyzBGt0Se5O7b3P36+PPHwPudfetwL3xZ4CfA7bGr1uAz0Mt9IBPAjcCNwCfnAo+EZELGhsHUEsswRodYmd6J/DFePmLwLvqyr/kNY8AHWa2GvhZ4B53H3T3IeAe4KY5rrOIJJSP1+ZKVEssuRoZYg78o5k9bma3xGUr3f1YvHwcWBkvrwUO1333SFx2rnIRkQvyeMJfU0sssdINPPbr3L3XzFYA95jZc/Ur3d3NbEaeixCH5C0AGzZsmIldishCEIdYkMtBsdDgysjFaFhLzN174/c+4A5q17ROxN2ExO998ea9wPq6r6+Ly85VfuaxbnX36939+uXLl8/0qYhIQqkllnwNCTEzazGztqll4K3ALuBOYGqE4c3At+PlO4H3x6MUXw2MxN2OdwNvNbPOeEDHW+MyEZELq2+JSSI1qjtxJXCHmU3V4Svu/j0zewz4upl9AOgG3h1vfxfwNmAfMAn8OoC7D5rZHwCPxdv9vrsPzt1piEiS+dg4HgS1R7FIIjXkN+fuB4CXn6X8JPDms5Q78Jvn2NdtwG0zXUcRWQTGxvBslvgPakmg+TbEXkRkzvjYKGjy30RTiInI4jU2jmtQR6IpxERk0fK4O1GSSyEmIouWQiz5FGIisniNjemaWMIpxERkUYqKRSiV1BJLOIWYiCxK1YGTAHheNzonmUJMRBal8OQAAK7ZOhJNISYii1L1ZNwSU4glmkJMRBalan/cEmtSiCWZQkxEFqXqqe5E3eycZAoxEVl0wjBk6OBBouZmokD/DCaZfnsisuj09PQw/OhjFKOIsfhxLJJMCjERWZSaowjy+UZXQ14ihZiILEpWLBLqRufEU4iJyKJkxSJVzWCfeAoxEVl0vFzGKhW1xBYAhZiILD7DwwBUmxRiSacQE5FFx4eGAdQSWwAUYiKy6PjQEABhVtfEkk4hJiKLjg/0A1DRDPaJpxATkUXH+/txM3UnLgAKMRFZdLx/AM/nwazRVZGXSCEmIouO9/fjzc2NrobMAIWYiCw+AwMKsQVCISYii4pHET4wQKQQWxAUYiKyqISDg1CtqiW2QCjERGRRqRw7DqAQWyAUYiKyqFSOHwPAm/UYloVAISYii0o1bonpmtjCoBATkUWlcvw4ZDKgx7AsCAoxEVlUyj3d2KpVutF5gVCIiciiUj54CFu3rtHVkBmiEBORRaNaKlHu7mZ8STuRe6OrIzNAISYii0b39u1QrdL7/F7GxsYaXR2ZAQoxEVk0/MgRAJqWdTW4JjJT5jzEzGy9md1nZrvN7Bkz+/dx+e+aWa+ZPRW/3lb3nY+b2T4z22NmP1tXflNcts/MPjbX5yIiyeK9vQCUW1oaXBOZKekGHLMK/Ad3f8LM2oDHzeyeeN2fuPsf129sZlcB7wGuBtYA3zezy+LVfwa8BTgCPGZmd7r77jk5CxFJHD9yBM9mifQcsQVjzkPM3Y8Bx+LlMTN7Flh7nq+8E7jd3UvAQTPbB9wQr9vn7gcAzOz2eFuFmIiclR/pJWpra3Q1ZAY19JqYmW0EXgH8OC76sJntMLPbzKwzLlsLHK772pG47FzlZzvOLWa23cy29/f3z+QpiEhCuDtRdzdRe3ujqyIzqGEhZmatwDeAj7j7KPB5YAuwjVpL7TMzdSx3v9Xdr3f365cvXz5TuxWRBKkePw4jI0RLOy+8sSRGI66JYWYZagH2ZXf/JoC7n6hb/5fAd+KPvcD6uq+vi8s4T7mIyAsUdu0CIOpUiC0kjRidaMBfA8+6+2frylfXbfbzwK54+U7gPWbWZGabgK3Ao8BjwFYz22RmWWqDP+6ci3MQkeQpPvMMBAFRR0ejqyIzqBEtsZ8CfhXYaWZPxWX/GXivmW0DHDgE/FsAd3/GzL5ObcBGFfhNdw8BzOzDwN1ACrjN3Z+Zu9MQkSQpPrMbu+QSSDekA0pmSSNGJ/4QONvMm3ed5zufAj51lvK7zvc9ERGoDeoo7tpF8KpXNboqMsP0J4mILGhhGNL92GOEQ0OMLeuCMGx0lWQGadopEVnQenp66P5M7fL7vp27NGfiAqOWmIgkXhiG9PT0nPq8YcMGUqnUqc9dE+NYUxO5lSs4NjLCZBiS1wCPBUEhJiKJ19PTwx994yFS7Ss41n+Sq9bvp6mljVLVmRgfY2X2EjZtXcuJiSL3F1ophyFvmjxKa3OzwizhFGIiMq/Vt7LqW1gjhQo/fL6Pe3Z089ThEbpHO/CBMtDG47tLQOn0Tq54OwDmEZ2VUTpO7uWesYj0RMCbJo+ytKODY0NDNKdSFN0VbAmiEBORea2np4fPfPMhAN790yV2Dqe577k+nugZInJImdPqBba0NbFlwxrGe/fS0pwjVZ4gnWthzeMP8vonH+Irr/kFHiqnGV26mcHVr6Kzo581J3ZwT3kZvWPtPH3SyDTlSadqwbbFnQ4NApn3FGIiMq+dGKvQa8s4NFLlO1/bD8DG9oDN+QIthX7Wr10FpRJBLs2mVe3s7wsJUhAZmMGlxw6RrxZZu2Y1G3ZtJ10dpDe3nL6OLRTW3MBlQ8+xdOkKmluXkM21Ui6Oc09lGY8OZvjQ0aNceumlDf4JyPkoxERk3oki5wf7BvjSQ4f4p+f6cKAjXWVLZoyXb1zFwP6ddKzdSFRsIzCIzrEfiyI2Hz3Evs7VENQGYwc4K4cPsCQqsa/zCvYuvYpXePkF32tp66CttXV2T1JmhEJMRBpu6rrXZKnCd/eM8O3dwxweKdORS/EvLq09+ysaGSLItbB+wwbKw8entd8VJw7TXC6yd+nqn5hhob08wiV9T3Fw5XU8UMygB7Qkk0JMRBpu74FDfPT2J9k3kaFMmmV543I7xkqqDB8o0LF244vep+Os3rOD0Ix9nSvZepZt2gonWTd2iEPtm1jfspqVoe4hSxqFmIg0TKFU4X/c/TR/s72PkXKerkyFyzsqvOplV7F/xyBBroWoOHFR+x4fG+fSvTs5kF/CuJ97XoeVE0cpd6znaNeVdPU/cbGnIg2iEBOROefufG/Xcf7g73dydLTCEib5qeUZOhknyLXMyDFWnzzB8uI4D6y76rzbGfD63ATfCNs51rqOlYXhGTm+zA2FmIjMianrXs+emOB/PtzHrhMF1rYGvGlDhpZCbXRhVJy5411z6FkqQYqdHSsuuO3SVMTS8V76WtfQMbSf7MxVQ2aZQkxE5sSz+w7y4dt3cKiQJUPEjaubyB7fTVvnxnOOLrxYqWqFq7qf5/mlayimMtMKpZVD+xhqXUP/kk20TfRc+AsyLyjERGRWhWHIVx7YxWcf7GWo2MQluSJXdQVcdsUm9lf7Z+WYV+x+nHy5yPbVW6b9nUxYYtnkCQba1lIuTG/0ozSeQkxEZs3wZJl//zc/5oEDo7RQ4nUrAjq8QBDMzHWvs4pCXvb4A/R0rqC7fRmMj0z7q6smeulvXsWJltWs9JOzV0eZMQoxEZlxYRhyx0O7+fR9RxkqVHn58hRrfZJ0U8uMXvc6my07HqVjfIS/XXcNleqLmzaqKSyxZOIEA80rCScGZ6mGMpMUYiIyY8IwZN+BQ3z23v3cfahCe9Z4Gd2sz60mLDrjIyOkyqN0pKG5fJIl0SBjIyOUyiG5TO4lHz8zPsprn36IQ+3L2bd01UUN0Oga62GkdRXHM50vuT4y+xRiInJ+7lAahfE+GD9BNHqMocN7CCb7SRVOkiqNYGGJICqzazTPx0fexV5fx7vTD/A72TvIB2Ok+6ukvErKvLbPIeCxM44zCGXSlMeyhEPNFKpQHm+i7CnK4zlKHlCeyJN9ZjnXjo0yMbmE4TBPifUMh00cHuli40PfJVsp8d2r3wCRX9TpthSHyFcmOJxZhvvF7UPmjkJMZJELC6Mcf+aHpIb2kRk7QqY4SFDoJ104WQup4kmC8PRjTQKgCwjdKFsTRc8QkeZvg7fymcLbaPYiHw1v45rsMAfabqCvr49quUihVCHd1EyxElImy8pVKznQc5T25iaC6iSZANJhgXwmYHVnM2NjfeTSRsZL5FNF2rxMLuW0jhxkczhJm5cJDKibZCO8xBhYmedd/gOOFPL02xr2hnl6yymGJycplMtkms4fTAasmDxG95JL2Tcc8c9m44cuM0YhJrKAveBZXMtaSA3ug/49MPA83v8c4fFnSU8cY239d1I5xqoZCkETE2GWMLWW0SgL6SZWrVnHU90jrFu9jKFShvZ8wIGxDLcOb+O5cA2bq4dYTx8PDq3kvpH1vKxjK9u7n6KzYwnFwiS5qLn2nm/muq6r+NHe7eSC02Wn1q24ih8d2P6CslPrXn4VP3pkO835HE2lQdozVVpK/bxveB9LW8oc7UpxVf4Yb2yfJLBdsBLKUUA/Xexel+GZ0gaeKi+lv5SmfI5QW1rop7d9E9/vLvOBOfpdycVRiIkk3AuCav16UhPHTwXVxIHtLN3/APlohFTdTO1RKsdEfg2T5Qx90VZaly7nZNhGprmNl19xKTuePkB7zhgtOu05Yyx+X71lE3vHDxAGRughf3+8gy8XbqRMhhvyvYztfphwxSoAWprSdLTlyTdlZuW8IwKGomYKQTPXHBki6s5y92vfxJf3j5JrbiYsjLG+rcq6oI8rl5R5eVeV69qP8pbMUVgDA5Uc9w+u4h/Gb6ztz51CuUSpXKLJCiwv9vPosVX0jRVZ0fbSr9fJ7FCIiSTQqeCKQkae+T4dz3yRtupJIpsgVR0/tV0+3UY108zJaC1D1Sb6K62E2VY2bd7Ko88d4fK17YwWnTBnTBaddjtzrvezGwsz/Gn/y3jKN5ErnWRbuJfXXLqJHx1un61TPqfWUpG3Hulmf9sSjq7fAAO7AKh4iqPVNg5MNvFouZnXdG3hvp072LjEuTLdy6uXDvKuFd28c3kPPyoe558KXeTzTlgeI0oVWDG6k1TXcvrHSgqxeUwhJpI0xVEGHr6d5of+jGXRcVJhEceYCNo5GnXSH22gkmljzSWX8cjefi5ftuRUi8qKztKcsWlNF4f7p3//VL0nCiv4Xye2MRY1sSXqZsnYMzTn8zN8ktPkztt3PUUqcr6zfjObLxjCxvFKC4dG1nNf4XJaK4O8b+1Bblr6AOuubOX/O/o6jhZT5NIBXakSv3x5gavXLJmTU5GLoxATme/cCfueY3j7N8gffpB83+OsjKqEQROpZZfy7Hgb1dbVDJUztE+1qHLGJevX0j1YuvD+p2kySvM7u9bxtZGlNFdHueT4g6zuaKJI40bw3Xikmy1DJ/na8tWcyGbZ/CK/P1DJ8Rd91zG+9Dre1nQnn9rwIP9pz/WM0Twr9ZWZpxATmY8mBwn338fkjr8nf/Rh0hPH6QJGvYUDwQYOhcvpWrmBbVdsof/pA7QHBrMUJu7w48lVfPnEtYx6MzeUn6A9KDLc9OJuJJ5pK8ZGuenwIZ5dspQfd3TxUjr8DrCFj+99Ff/v1sf5vUuf4BOH3wg0qHUpL4pCTGQ+iELCnh8z+sQ3yfc+RNPJ3aRw8mQota7jyehqWlZsZKDaQnvOyBQdpnn96qU4Vsnxh/3X8Ey4jubqCG9dcoCeA3vIxoM3XoqIiDBVpZwtUGSScq5AMTXBZHOaPdWQwa6jpHMZKtUimXwTlbCEpQKIhhha1ctVx49xx40pfrislcnCEOVUie5MjsKScYJMQFgKCd0Jo+mF7fOTS/ij3hv4v9c/xG+tfoK/HtHg+iRQiMmMe8FouQ0bSKVSDa7R/BOGIUf27aLp8I9o7v0BLUcfIlUapgM46R30pC6lp9LFsjXr2XbFFgpPHyCTNqjOTdfdZGjcfnQj/1i6mghYefIJLs2NcvnlV9J/qI0wVaGcK1JuKlJMjTPRkmJXWKB/zSEsF1DxItZkDNpeBq4+CRkIrYJnIsKgiqcjng7uhp86+/EPsxOuPvu6fg7AZXDHZVMlR0+t6+MgrIOpWQ+tnMImUjSV8jyemWBi1SjpYgafdEJ3qlFI6BHFSoUwCtkxuYLberfywXXP80xpH2H4hhn6icpsUYjJTwjDkL0H9zJeHWfJiiWMl8fZ37ufQligWC1SiSqEhLQsaaESVShHZcph7TU6Osro2Cj7h/cDsLFjIy0tLUQe0dbWRjpIUxwvEhCQshSZVObUctrSp8rSpMkEGTKWIR2kyaVzrFu9jlw6RzaVJZvKkiJF/7F+Ag/IBBlymRwpS83f4HSHgefh+e9R3vFtNpx4AsMpk2GybSM7CxtpW7Xp1LWt7Cy3tkKP6Bsf53i5gkUhxysVhiYK/OkT7fyw/01UaKcps5vOpfcTrj3Jc9mIPen7Kb2+WLsj+AxHAC4FIrBqgIVpqkxQtgqpSgYvGymasWJIxnKs7FrK0UMDZFN5qhMV8tkWKhMVmtLNXH7ZJex6Yi+5pmZKE0UymWZK4xOsTWf44NEjLB0c4iuXrOehbJZcW45CaYJsexObtyzjmf2HSLemKQUTpJYYlUyRcnuB3S3PwU/BEEdJD2XJDrbDvgxhmKHfxpmwMpkw5GvH1vKqzgHet/QJvt73+ln7+cvMUIgtQpWowuGRwzxx4Al6J3rpK/UxWB5kqDzEUGWIk8WTlHz6AwIMIxNkCDygGlXBwVKGudE30kdqIoWHTm4gR+ghxbBI5BFujtuLaFnsnEZdvFaXbCpLxjK1IJx6WeYFwZgNattMbduUaiKXyrGyayX5TJ58Ok9TqolskGXs5BjZVJZL1lxCS7aFXDpHU6rp1DapoBaa9a1QgA1rVkD3jxh/4ps0H3mQzHhvbbvWjQx3vozuShe0dLHtii1Un67dfxV5xNjYOMOliEy2heGwxCAlTk5MMlwJ6cjlGU1FZANnsnCMHZlBMgGMZKpUK0WGCSGM+PvjxziYHiayiIlcBFljIhNSokr58OOMdJbxOIzcIZy4nFLfzxONrSHId9O89KtkUkeoVjNQgnQhR1dbBwNHRshanupElXyqlep4lVyqhasu28yOh/eSy7VQmiyQa27m2m1beOyhneSamylOTr7g/bL2LYx0v3Adk5Nkm5tpjdpJTWZJkcXKVdaVS9zYe4LXDQ9DKuDPl63i+bal2MQkQTlNMJkhYzk6S0vJHO8j39KMTWTJtzRTmJgk39LM1Vet4ZH9u7C1IcXOESY3DcAWKI8McbzqeOAUggpFqvzRsZfxl5t/yFvG/w6i/wLBPPyjSACF2IJWKBd4eM/DHBw7SPdkNz2TPfQWeukr9hHVPYbQ3MiGWbKeZUnLEjrGOmhvbydVSVEpVAjKAZ3LO9m4ZSNHdh8hnUtDESbHJvGik8qluGTrJRzaeYjODZ1EhYigKai95wO2XLWFvY/vZWx4jKgYnd4mH7D5ys08/8TzWM4IiyHkYMNlG9i/Yz/koFqsQhOEpZDxwjjL1i7jWPcxyEBUjcgtzRFWQjzjdKzooP9oP8VCkSiM8LQThiHVdBVvdYZGh/CUE3lEFES4O1EQEWQCKtUKkUVEFsH5nof49NmLU5YiIMAcNpaKvKpU4sbJSVYWCzS702TGo9k8jyxZxvbWVroxMukJqowTcZDg8BOUl4Q4EDY5VfPTrZ3ex+DMuWinxhz074bWeLnphZs0lQYIshFZh1RkdJRzNIVGU7XCyrY8Q71FOtNpTkxs5UDlzYzbBjLRGK/s3EPfkw/TnF9KcTL3gpC5dtsWHtv7k6GUac6T82YsCrCzNdMugrtz+dAQP3P4MJcWClTM2N7ZwYHXX8fTu7tf9LCLlKdJD+bIl5pJTbTQ1JFlrGuA6uYJnuvajb0twLuXYc/m6avm+cuhl/ORrsfh4IOw5U0zck4y8xRiC8R4aZwHnn2A50aeY9/4Pronu+md7D0VVuZGrpoj73kuX3I5xWNFlnUtI1fKkcvl8NAJmgO2XFkLnCAVEJUjgs44jIKArnwXgwwSWEBERG5F7lQYLVu7jKHjQ+et45IVS4gKL3yGr5kREBBY7R+/wAJaMi3kyZ86ThDU3pcuXcqWTVvIDeYI8nG9puqZCtiycgt7j+wlaDsdoKeCdOq88mesy50O2SAfEBZCRsdGqZaqeM5ZtWkVh58/TMuqFirlChOFCaqVKmRr59N/tI8NNsk1xWGuLQ/x8uo4nV4F4JhluD9o5mFvYl9znrHIyLjRmWpi+WCBrlyeamhUquMs7cxx/PgYuZRRrjhtTSkqZch5yLpVnXQfHKSjOUOx6DQTUiw47Vlj66YVPLPrOEuyAZOTESvbm5gcj1iWC3jFKzdz/2P76WgOGJ6MaA4mGZmMWL40xzWvWMf/GsizI/c6jtp60uEYbcfvY03qJJtWb2bAZ3/QyDm5s7bnKB/bt4+NxSL96TTfXLOGB3I5ovY2XtY8M6MGg0qa7P522o+vZMO2Np60HYxf3oddEsD+ldw/uJYVS17DLyvA5jWFWIJMdVWVq2UOTx5m/8R+9ozuYe/4Xnomek4FVjbK0tXUxcrxlSxbsoyWUgutuVYIqQXVZVvYO7b3VDiYGd7Ae33mE8PoXHG6pbhpwyaq/dXaz8oj1i7pYM3wcdaO9nJNqYdVI0dopzad02iYYt9klh9V28hecgn3PdnH5lU52icjfjoOko7mgG2r13H/wf00B6OnQmXbmjXc33s6cE6/Z9m2ZQX3D4/RUT5dNlyI6LCAa1o7GagO0pENGCaipWpUIjtrayiby1IK83yv9Cr++67XMppvpS0c4Jr+rxJkcoyWRrHmxt4fta5Q4Be7u7l8dJSBTIYvb9jAg9ks2daWWrfgLBzTMDpLS2nZvor0GhjZeoyxq49RnBxkO8t5rzs2ByNB5eIoxOa5arXK43sf5/mx53n86OM8PvQ4o4wSBbXASkUpWsNWVhZXsrJjJW2lNvL5/OnWRRxUU60amT5zZ8l4P68c38vaE0fZXBlgvY+SigN/rJxjz2iKE1Enz4xk6FzWwnDR46DqYun+4fPuP5vLkolm/3cyQTO7UlewL7yGo21bcEvR5QN0HLyf9mo//YUCncuXz3o9zqW9XObaoSFu7Onh6pERxlMpfviKq/jSaJGmtjbCick5q0tmpJnmB1aR2hQxcUUf97Tcw8PHHua1a147Z3WQF0chNs/0T/TzwHMP8Pzo8+wd28uekT2MRbVnTZgb7al21oZrWZJawrVbr6VvVx+p5hSRne52kxfPPGJFeZTV4ydY1XecDeVBLvER8ntrXYNlN3oKGR4JW9k7niFob+PKV17K/T+stZ6sOaJ2EavxLdpKFLBrfDVP7r+S7Zk30B9sxptTZCqj5PufYhV9XHftSh7bd5JcaytBEMxNxdxZUiqxYXycVeNjXPvgSW7a38Oacq0lO5JO862lnTy0Zi1br9hEtP25uanXGQyjqa+NrokuNl3fxWtWv6Yh9ZDpUYg1iLtzsniSZ08+y67+XTze+zj7x/YzUB6IN4BclKOl1MIVrVdw9ZarGXp2iHQ2TVSpBVZHUwf99Df2RBImHVVpLw2z5GQfq0rDrAnG2XikSNfkSZqo3RRbceNYKc3usAlbvoEf7BmjZWkrQ5O1VtZwOqKDOfqH/wKqbpwMVnDY1tKdXUV/tJoTbesJgyYYh7QP0Da0i/TAcyxvCyjFo/9g5azWKxVFrJoYZ+Oz+1jX28uGapV1ExO0hqdvPK6kUjzXlOXHy1azM0gx0LWUyckC+fT8GAloGJurm9WVOM8lPsTM7CbgT4EU8Ffu/ukGV+kUd2eoNMTxieMcHjnMAzt/QG9hiKOFYQZKkxTDFB5lIcqSqjaT4wbSY2ma0m1YuQmCDJPVFIdSASeOtzIxMokHAR6CBwE/OpRncmIbmBFFhgWGR2ABNB3IUppsw4JaPcwAdyyAHxzKUZporj3dMN7eo9q6h7pzFMavxQKDyLGUY1GEBc7jR/NMDl9GkHYII4IUWBSRa8vQXepguH8L1UoJqmFtm2pEkHF6x42TRztJZYBKSJAFq0a0LsvjvXlOTHSRqkJUqlI6OUk5mOT4MWhflccqTiowqFRJpY3JYkA5TJMODY+cIIpoDou0liusGOzBJntInRwjXyrQmq7SWinSFRRZdSSkdXLo1PWrKSOlFEVvZftwjiHPsm88TWtdYG1bv4ly936aG9DKijAmaKGn0MmR1GZ6rY3j6XZGKp0MZpYySRcTOzqJWmqBGmTKZCqjZEf2sDQY47rLW9nxyFO1EYSpIjZT8wG6k6tW6SgWWVYp0zI6RtfQEJtHB3jFkT5WVausKBSYiqKyGcdzOZ5oaeZ4WzvdHjHW0cGGa7fwyBN7Tg+DV1jIRUh0iJlZCvgz4C3U7rV8zMzudPfdM7F/d6cYFpkslxgrTTJeKjBWnGCyVKBQLjA0McHA+Bgnx8bpPtbHRLnKeDGi7GmK1RTlqIlqmKcSNVMNm6n4+bslJuL3wKukvEKaKkFUIWUQVo2wlCIwg6iKEeFhkUxhsvaXYlTFggCPIghSZKIc0WQBggCPvPbujqVSmBtWKMfrIjxIQRQRmVEOK0SFEEulwCOcAPc0HqQoV9JUK20QpIjccAtwC6BsHB5KEUbriTwum7rNrAT7xgE2QDEum3rviV+seOEPYhDgSth3lh/SswDrX1BkRKSJSD9XJc0rSRER4AREBEQYEQZEUQQeEblj5lRDJzBoJs2ElUinnLDdSUdOmHEyodOyO8topkgmdKrpWlmYdtJV+NazTQynbiRdhTAVkalANeVkKs5dz+UZDF5BumJUAovfIVUx7ny2mcHUjaSrRiUFqWrA13a3Mph1Im+inM8QWhOl1nztL4zn4VT+5CEVFgmKwzSVh9nUPsxg935aozGikeMsXb7s1ND3lnATzdUqreUyLeUyLWZEhQItYciqoye4cmyMfLEIk5Pkx8ehWKQlnWZjYYTLDx+nxYxMuUzOjEy1Ss6dlp1P875CiSb/yUAvZjMMYAzkcmzP5ehb0k7b1Zv4/p4jNE0NzJgKrGyW9YFCS166RIcYcAOwz90PAJjZ7cA7gRkJsYd/cCe/clftn8Jza4tfqwEIiGhngg6bYBVjdNggHfTQEYzTYeN0ME6HTdDBGEtsglaK5K1EnhJ5yjRRJnWuG4DP9mzB7Hmqdr5153vs0/m+13SedbHIjSoB1VoMx++p2rJPlaWokCYkOPVe9Z8sK4dpKlGaSpSiEsbv1fSp8nKYqq0P01S9tj6MAqpRQOi1OIssIDKLX3WfOf3ZAY+3cQyP36PRMk2kTn+20+tKBaOJJtxqYwEjCwCjYtA3YLgtpVpxDKiEjuFQdcb6nSbyUIYMjrnTNFZhc1imqTpMPiyRq5ZpK0/SURqvvcrjLCmNs6wwTEv1PDeiHzp4evmxx8693e5z/y9SPWKMmDGZSlFwKKRSDLpTSadJt+Y57gFjTTn6wpDx5mZOVCqMt7SyZsMK9j7fQ7a5mfLkJFlPccnwJEMj42QrEeXJSQrl8NT7wZ4TjAyPvaBsPq0rTs7dgBK5eOZn+YsqKczsF4Gb3P3fxJ9/FbjR3T98xna3ALfEHy8H9sxpRWffMmCg0ZWYBTqv5FiI5wQXd14D7n7TbFRGflLSW2LT4u63Arc2uh6zxcy2u/v1ja7HTNN5JcdCPCdYuOe1kMyPIVYXr5cXXiBZF5eJiMgikPQQewzYamabzCwLvAe4s8F1EhGROZLo7kR3r5rZh4G7qQ2xv83dn2lwtRphoXaV6rySYyGeEyzc81owEj2wQ0REFrekdyeKiMgiphATEZHEUoglhJndZGZ7zGyfmX3sLOs/ama7zWyHmd1rZpc0op4v1oXOq267f2lmbmaJGO48nfMys3fHv7NnzOwrc13HizGN/w43mNl9ZvZk/N/i2xpRzxfLzG4zsz4z23WO9WZmn4vPe4eZvXKu6yjn4O56zfMXtUEr+4HN1ObTeBq46oxt3gQ0x8v/Dvhao+s9E+cVb9cGPAg8Alzf6HrP0O9rK/Ak0Bl/XtHoes/Qed0K/Lt4+SrgUKPrPc1zewPwSmDXOda/DfgutUcVvBr4caPrrFftpZZYMpyaXsvdy8DU9FqnuPt97j41T84j1O6Zm+8ueF6xPwD+kNOzLs530zmvDwJ/5u5DAO7eN8d1vBjTOS/n9KRmS4Cjc1i/i+buDxLP2nkO7wS+5DWPAB1mtnpuaifnoxBLhrXA4brPR+Kyc/kAtb8a57sLnlfcbbPe3f9hLiv2Ek3n93UZcJmZ/cjMHomfxjDfTee8fhf4FTM7AtwF/NbcVG3Wvdj/B2WOJPo+MflJZvYrwPXAP2t0XV4qMwuAzwK/1uCqzIY0tS7FN1JrNT9oZte6+3AjKzUD3gt8wd0/Y2avAf5/M7vG3fW0VpkVaoklw7Sm1zKznwE+AbzD3c8z1fm8caHzagOuAe43s0PUrkXcmYDBHdP5fR0B7nT3irsfpPbAla1zVL+LNZ3z+gDwdQB3fxjIUZtEN+k0xd08pRBLhgtOr2VmrwD+glqAJeH6ClzgvNx9xN2XuftGd99I7VrfO9x9e2OqO23TmQ7tW9RaYZjZMmrdiwfmsI4XYzrn1QO8GcDMrqQWYgvh8eN3Au+PRym+Ghhx92ONrpSoOzER/BzTa5nZ7wPb3f1O4L8CrcDfxo9T73H3dzSs0tMwzfNKnGme193AW81sNxAC/9HdTzau1hc2zfP6D8Bfmtn/SW2Qx6+5+7yfFsjMvkrtj4pl8fW8TxI/wc/d/5za9b23UXtU6yTw642pqZxJ006JiEhiqTtRREQSSyEmIiKJpRATEZHEUoiJiEhiKcRERCSxFGIiIpJYCjEREUms/w3ey8pahjsyBQAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "df_rewards = pd.DataFrame({label: bandit.rewards for (label, bandit) in bandits.items()})\n", - "df_rewards[\"oracle\"] = bandit_oracle.max_rewards\n", - "\n", - "sns.displot(df_rewards, kde=True)\n", - "\n", - "(df_rewards\n", - " .cumsum()\n", - " .plot(color=[\"red\", \"blue\", 'green', \"cyan\" ,\"magenta\"])\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 190, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 190, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXIAAAEECAYAAAA1X7/VAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Il7ecAAAACXBIWXMAAAsTAAALEwEAmpwYAAAYTElEQVR4nO3df5xV5X3g8c9XREfEigVeakMQ1mTRglBhEH8gaqqE1SQEzS/3VYVNKLZrmsTatRoTiTFNs9V1XdxmfRGDJv7YbqKiiT8SpFuLWlBmCFgEDd3UH9hUkVoUXDcQn/3jHnAYZpgzcw4z5wyf9+t1XnPuued57vc89873Pve5zzk3UkpIkurrgL4OQJJUjIlckmrORC5JNWcil6SaM5FLUs2ZyCWp5gon8ohoioinI2JNRDwbEdeWEZgkKZ8oOo88IgI4NKW0NSIGAk8AX0wprSgjQEnS3h1YtILUeCfYmt0cmC2eZSRJvaRwIgeIiAFAK/AB4C9TSk91sM88YB7AoYceOum4444r46Elab/R2tr6ekppePvthYdWdqssYgiwGPijlNLazvZrbm5OLS0tpT2uJO0PIqI1pdTcfnups1ZSSv8K/A0wo8x6JUmdK2PWyvCsJ05EHAKcAzxXtF5JUj5ljJEfDXwvGyc/APhBSunBEuqVJOVQxqyVZ4ATS4hFktQDntkpSTVnIpekmjORS1LNmcglqeZKObNTknrLqCsf2u32C986r48iqQ575JJUcyZySao5E7kk1ZyJXJJqzkQuSTVnIpekmjORS1LNmcglqeY8IUiV5YkfUj72yCWp5kzkklRzJnJJqjkTuSTVnIlckmrORC5JNWcil6SaM5FLUs2ZyCWp5kzkklRzJnJJqjkTuSTVXOGLZkXE+4HvA0cCCViYUvpvRevtC16kSVIdlXH1wx3A5SmlVRFxGNAaEY+mlNaVULckqQuFh1ZSSr9MKa3K1t8C1gPvK1qvJCmfUsfII2IUcCLwVAf3zYuIloho2bRpU5kPK0n7tdJ+WCIiBgP3Al9KKb3Z/v6U0kJgIUBzc3Mq63GrpP0YOzjOLmnfK6VHHhEDaSTxu1JK95VRpyQpn8KJPCIC+C6wPqV0Y/GQJEndUUaP/DTgIuBDEbE6W84toV5JUg6Fx8hTSk8AUUIskqQe8MxOSao5E7kk1ZyJXJJqzkQuSTVnIpekmivtzE5JUn5lXm3VHrkk1ZyJXJJqzkQuSTXnGHk/5C8dSfsXe+SSVHMmckmqORO5JNWcY+TSPuZ3FtrX7JFLUs2ZyCWp5kzkklRzJnJJqjkTuSTVnIlckmrORC5JNWcil6SaM5FLUs2ZyCWp5kzkklRzpSTyiFgUEa9FxNoy6pMk5VdWj/x2YEZJdUmSuqGURJ5SWgb8Sxl1SZK6p9fGyCNiXkS0RETLpk2beuthJanf67VEnlJamFJqTik1Dx8+vLceVpL6PWetSFLNmcglqebKmn74P4HlwJiI2BgRnyujXklS10r5zc6U0oVl1CNJ6j6HViSp5krpkUtSn/na4e1ub+mbOPqQPXJJqjkTuSTVnEMrqg8/QksdskcuSTVnIpekmnNoZV9zOEDSPmYi3xuTsKQacGhFkmrORC5JNWcil6Sac4x8f+BYv1R97f9PIff/qj1ySao5E7kk1ZxDK1JvK/ARWuqIPXJJqjl75JL2O6OufGi32y9867w+iqQc9sglqeZM5JJUcyZySao5E7kk1ZyJXJJqzkQuSTVXiemH/W0qkCT1pkokcknqUzW/sFwpQysRMSMino+If4iIK8uoU5KUT+EeeUQMAP4SOAfYCKyMiB+llNb1uFKvRSFJuZXRIz8J+IeU0i9SSr8C/gqYWUK9kqQcIqVUrIKITwAzUkpzs9sXAVNSSp9vt988YB7AyJEjJ7344ouFHre9Pb4wbfr3u+9Qkx59VY6jaBzty/ekjjKU0Z5VeE6qcBxlPKddxpCjjiroq9d3RLSmlJrbb++1LztTSguBhQDNzc3F3j1UTzX4B5XqqIyhlVeA97e5PSLbJknqBWX0yFcCH4yI0TQS+GeADj4vaX/iuQBS7ymcyFNKOyLi88BPgQHAopTSs4UjkyTlUsoYeUrpYeDhMuqSKs+xflWM11qRpJozkUtSzZnIJanmvGhW1TkeK6kL9sglqebskWv/4icc9UP2yCWp5uyRKx97slJl2SOXpJozkUtSzTm0Ikll6MPhRxO5tL+qwvceVYihH+i/idwXiKT9hGPkklRzJnJJqrn+O7QilaSSv3bk0KHasEcuSTVnIpekmjORS1LNmcglqeZM5JJUcyZySao5E7kk1ZyJXJJqzhOCKqaSJ59InfHEpEoo1COPiE9GxLMR8W5ENJcVlCQpv6JDK2uB84FlJcQiSeqBQkMrKaX1ABFRTjSSpG7rtS87I2JeRLRERMumTZt662Elqd/rskceEUuBozq46+qU0gN5HyiltBBYCNDc3JxyRyhJ2qsuE3lK6ezeCESS1DNOP1S/5nRO7Q+KTj+cFREbgVOAhyLip+WEJUnKq+islcXA4pJikST1gKfoS1LNmcglqeZM5JJUcyZySao5E7kk1ZyJXJJqzkQuSTXnmZ3qkGdESvVhj1ySas5ELkk1ZyKXpJozkUtSzZnIJanmTOSSVHMmckmqORO5JNWciVySas5ELkk15yn6ktRNVbuERb9J5FVrWKlq/B/pvxxakaSa6zc9cknV56eCfcMeuSTVnIlckmrORC5JNVcokUfE9RHxXEQ8ExGLI2JISXFJknIq2iN/FBiXUhoP/By4qnhIkqTuKDRrJaW0pM3NFcAnioUjqSPO9tDelDlG/lngkRLrkyTl0GWPPCKWAkd1cNfVKaUHsn2uBnYAd+2lnnnAPICRI0f2KFhJ0p66TOQppbP3dn9EzAE+AvxuSintpZ6FwEKA5ubmTveTJHVPoTHyiJgBXAGckVJ6u5yQJEndUXSM/L8DhwGPRsTqiLilhJgkSd1QdNbKB8oKRJLUM57ZKUk1V5mrH27fvp2NGzfyzjvv9HUoldXU1MSIESMYOHBgX4ciqUIqk8g3btzIYYcdxqhRo4iIvg6nclJKbN68mY0bNzJ69Oi+DkdShVRmaOWdd95h6NChJvFORARDhw71E4ukPVQmkQMm8S7YPpI6UqlELknqvsqMkbc36sqHSq2vrIsOnXvuudx9990MGTKk032uueYapk2bxtln7/Wk2A499thj3HDDDTz44IMFopS0P6lsIq+alBIpJR5++OEu9/3617/eCxFJUoNDK23ceOONjBs3jnHjxnHTTTfxwgsvMGbMGC6++GLGjRvHyy+/zKhRo3j99dcBuO666xgzZgxTp07lwgsv5IYbbgBgzpw53HPPPQCMGjWK+fPnM3HiRE444QSee+45AJ5++mlOOeUUTjzxRE499VSef/75vjloSbVnjzzT2trKbbfdxlNPPUVKiSlTpnDGGWewYcMGvve973HyySfvtv/KlSu59957WbNmDdu3b2fixIlMmjSpw7qHDRvGqlWr+Pa3v80NN9zArbfeynHHHcfjjz/OgQceyNKlS/nyl7/Mvffe2xuHKqmfMZFnnnjiCWbNmsWhhx4KwPnnn8/jjz/OMcccs0cSB3jyySeZOXMmTU1NNDU18dGPfrTTus8//3wAJk2axH333QfAli1bmD17Nhs2bCAi2L59+z44Kkn7A4dWurAzsRdx8MEHAzBgwAB27NgBwFe/+lXOOuss1q5dy49//GPnh0vqMRN55vTTT+f+++/n7bffZtu2bSxevJjTTz+90/1PO+20XQl469at3Z5lsmXLFt73vvcBcPvttxcJXdJ+rrJDK739G4UTJ05kzpw5nHTSSQDMnTuXI444otP9J0+ezMc+9jHGjx/PkUceyQknnMDhhx+e+/GuuOIKZs+ezTe+8Q3OO8/fY5TUc7GXH/XZZ5qbm1NLS8tu29avX8/xxx/f67EUsXXrVgYPHszbb7/NtGnTWLhwIRMnTtynj1nHdlL/0NG5Hf4odO+KiNaUUnP77ZXtkdfBvHnzWLduHe+88w6zZ8/e50lckjpiIi/g7rvv7usQJMkvOyWp7kzkklRzJnJJqjkTuSTVXHW/7Pxa/jnZ+erb0uUugwcPZuvWreU+bg+NGjWKlpYWhg0b1tehSKo4e+T7wK9//eu+DkHSfsRE3onrr7+eyZMnM378eObPn79r+8c//nEmTZrE2LFjWbhw4a7tgwcP5vLLL2fChAksX76cwYMHc/XVVzNhwgROPvlkXn31VQA2bdrEBRdcwOTJk5k8eTJPPvkkAJs3b2b69OmMHTuWuXPn0hcnakmqJxN5B5YsWcKGDRt4+umnWb16Na2trSxbtgyARYsW0draSktLCwsWLGDz5s0AbNu2jSlTprBmzRqmTp3Ktm3bOPnkk1mzZg3Tpk3jO9/5DgBf/OIXueyyy3ZdBnfu3LkAXHvttUydOpVnn32WWbNm8dJLL/XNwUuqneqOkfehJUuWsGTJEk488USgcSr+hg0bmDZtGgsWLGDx4sUAvPzyy2zYsIGhQ4cyYMAALrjggl11HHTQQXzkIx8BGpevffTRRwFYunQp69at27Xfm2++ydatW1m2bNmuS9yed955e73OiyS1VSiRR8R1wEzgXeA1YE5K6Z/KCKwvpZS46qqruOSSS3bb/thjj7F06VKWL1/OoEGDOPPMM3ddfrapqYkBAwbs2nfgwIG7fvW+7eVr3333XVasWEFTU1MvHY2k/q7o0Mr1KaXxKaXfAR4ErikeUt/78Ic/zKJFi3bNYHnllVd47bXX2LJlC0cccQSDBg3iueeeY8WKFd2ue/r06dx88827bq9evRqAadOm7Trl/5FHHuGNN94ofiCS9guFeuQppTfb3DwUKO8buhzTBfeV6dOns379ek455RSg8UXmnXfeyYwZM7jllls4/vjjGTNmTIe/HNSVBQsWcOmllzJ+/Hh27NjBtGnTuOWWW5g/fz4XXnghY8eO5dRTT2XkyJFlH5akfqrwZWwj4s+Ai4EtwFkppU2d7DcPmAcwcuTISS+++OJu93t51nxsJ2n/1dllbLscWomIpRGxtoNlJkBK6eqU0vuBu4DPd1ZPSmlhSqk5pdQ8fPjwIsciSWqjy6GVlNLZOeu6C3gYmN/VjpKk8hT6sjMiPtjm5kzguSL1eRLM3tk+kjpSdB75tyJiDI3phy8Cf9DTipqamti8eTNDhw7dNW1P70kpsXnzZqctStpD0VkrF3S9Vz4jRoxg48aNbNrU4XelovFmN2LEiL4OQ1LFVObMzoEDBzJ69Oi+DkOSasdrrUhSzZnIJanmTOSSVHOFz+zs0YNGbKIxy6Uzw4DXCz5Mf6mjCjFUpY4qxFBGHVWIoSp1VCGGqtSRp/wxKaU9z6hMKVVuAVqsozoxVKWOKsTgcdgWVWwLh1YkqeZM5JJUc1VN5Au73mW/qaMKMVSljirEUEYdVYihKnVUIYaq1NHj8n3yZackqTxV7ZFLknIykUtSzZnIJanmTOSSVHOVSOQRcXhEfDoi/jhbPh0RQ0qo95xu7PsbEXFsB9vHd6OOoyLiqGx9eEScHxFj85bvpM5vFig7OovhuG6UGRkRTdl6RMR/iIibI+IPIyLX1TIj4mM76ygiIqZl17snIk6LiD+JiPO6UX5wRHwiIi6LiC9ExIyIyP2aj4gDI+KSiPhJRDyTLY9ExB9ExMCeHFNfiIhBEXFFRPyniGiKiDkR8aOI+IuIGFyg3p+XGWddRMS/iYhFEfGN7DX2neznL38YEaP6IqY+T+QRcTGwCjgTGJQtZwGt2X1FfDdnDJ+i8etG90bEsxExuc3dt+es4xJgObAiIv4QeBA4D7gvIj6Xs44F7Zabgf+483aO8ve3WZ8J/G/go8ADETEnTww0fq5v5+viW9kxPAVMJv/0qP8FbIyIOyLi3IgYkLPcLhFxU/b4d0TEdcD1wCHAZRFxfY7yn6Jx/DNo/JbsZOAiYHVEnJAzjDuA3wG+BpybLdcCE4A78x9NpzF22Z4RMSB7M7kuIk5rd99Xcj7U7cCRwGjgIaCZRnsG8D9yxvpWRLyZLW9FxFvAsTu356xjfJv1gRHxlewN5ZsRMShH+c9HxLBs/QMRsSwi/jUinsr7nEbEfRHxe0XewGi050pgK7CCRu74d8BPgEU54zggIj4bEQ9FxJqIWBURfxURZ/YooqKnpZZwWuvzwJAOth8B/DxH+R91svwY2JYzhtXA0dn6SdkTMyu7/bOcdfw9jTehodkTfFSb41ids46XaSSIi4HZ2bJp53qO8j9rs/53wOhsfRiwJmcM69qstwIHtLmdt46fZcf9+8BfA68CtwBndON18SyNRDMIeAMYlG0fCKzNUf6ZNmWGAT/N1scDf5czhk5ff3lem9l+v9nJMhTYmKP8rcDdwJey5+PGNvetyvv6zv4G8M+8N+04gGdy1rEA+D5wZJtt/5j3+WwfL/BfaCTEM4D/Cnw/z2uizfpDbf5HzwSezBnDK8A9wL8APwBmAQd18zh+1mb9pc7u66KO22h0EKYCNwFfB84BlgJ/1J14UkqVSOQ/Bw7vYPvhwIYc5d+g0Ws8o91yJvBqzhj+vt3to7N/mi9045+l7Yt0Tbv78j65h2VP6t3Ab2XbftGNtmwbw9M9jOGnwIey9XtpXKSHLPHkTeSr2t0+KmvL5cDLOetYm/1typ7jQ7LbA2jzZrO357RNwjqk3T9fl28E2X4rgE+y+5vZAcCngady1vFr4BfAP7ZZdt7+VY7yz7RZP5DGp6L7gIO78ZyubrO+qN19uZ7TbN9JND7lfCFrh9yvzfavQRqdp4HZeq43FOD5NusrO2unPDEAv0HjE9rDNDpLtwHTc9bRCvxbGp/yXgeas+0f6EYcz7S7vSL7ezCwvjvtmlKqxC8E/RmwKiKW0OiRAoyk8e50XY7yK4C3U0p/2/6OiHg+ZwxvRcSxKaX/A5BS+mX2Eed+IO8Yd4qIgSml7TTeWHbG0ETOIayU0lvAlyJiInBXRDyUt2xmQvYxN4CmiDg6O5aDaCTAPOYC34+IrwFbaAxFrAaGAH+cs47dfnQ1pfTPNHp0CyLimJx1PBQRj9NI5LcCP4iIFTTeoPd4rjvwMPCTiFhGY3jlhwAR8Zvt49uLzwD/Gfh2RLyRbRsC/E12Xx6/AH43pfRS+zsi4uUO9m/voJ0rKaUdwLyIuIZGQs07PNASEYNTSltTSp9t8/jHAm/lrIOUUmtEnE1jqOpvaTw33XF4RMyi8Zo+OPtfIaWUIiLPmYn3RMTtNHqviyPiS8Bi4EPAHu3biZQ95ps0hs7uiIihNN6wrwSW5KjjChqf+N8FPg5cFRETaLw5/H7OOLbvzDnZ//uvsrj+X8622F13M/++WGh81PwKcHm2fIbGR/Mzu1HHb3ewLVd5GmOeH2xfB42P8RflrGNktn/7On4LOKeb7fHbNJLNpcCd3TmWbN+x7W4PAa7sZgwnADOBC4ApNP758rbnmUWfk2zfU4DTsvVjgT8BPgWclbP8ucDVbds/a9cZPXiNDgWG9qDcpcCETu7r8iM0jaG2PeKl8Ya7vbvxdFBP9LDc0cC53SxzW7vlyGz7UcBf56xjDo3vbF6n8Sa0DvgmHXyq76T8sqJt1km9w4AB3dh/55vPBhqfzqZk24cDf9Htx98XB9XDhlgL/CnvjYveDCzvYflDulu+gnVcUbAtrqjIcVShLQrF0Em93XpzrupSxnH0l7bo7fbMXpPDynjcPp+10sYU4P00vqR7Gvgn4LS9lui8/MoelK9aHSMp1hY7y/f1cVShLYrG0JFcM6L2JroxPXZflM8UPo4y6qhCW/R2e6aGPX5IoidxVGGMfKftwP+l0WtqovGN+Lu9WL4/1VGFGKpSR4/LR8SPOruLxlBLUd+l8Sa1T8uXcRz9pS3KqKOKbVGlRL4SeIDGN8HDgFsi4oKU0id7qXx/qqMKMVSljiLlTwd+j8Z00raCxjTVLhX9py8paRQ+jjLqqEJbVKU9y34zqFIi/1xKqSVb/yUwMyIu6sXy/amOKsRQlTqKlC9jRlTRf/oyknAZx9Ff2qIq7VlGHO/p6y8HXFyqvlBsRtQjdDLLhhwzKIqWL+s4+ktbVKU9y4wjpQrNWnFxqepCObNvik7FLCMJV2UmUhXaoirtWTiOlKo1a0WqqjJmvvwgIv40Gg6JxnV0/rwXy0N1ZiJVoS2q0p5lxGEil3IoY/ZN0X/6MpJGFWYRQTXaoirtWcr0WBO51LWVNP5hJ9P4kurCiPhhN+uowpTSMo6jv7RFVdqzjDgcI3dx6WohuyhSu225Lt3QZv81NK4RMpDG6e0PAD/srfIlHkd/aYuqtGfhOFJKu64OJ2kfiojm9N40yJ3bLkop3dEb5aukCm1RlfYsKw4TuSTVnGPkklRzJnJJqjkTuSTVnIlckmru/wPiKGJF+NuhzgAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "pd.DataFrame({\"original\": {feature_name:beta \n", - " for (feature_name, beta) \n", - " in zip(dataset.feature_names, dataset.beta)},\n", - " \"learned\": bandits[\"ucb\"].best_model[\"LinearRegression\"].weights}).plot(kind=\"bar\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "river-env", - "language": "python", - "name": "river-env" - }, - "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.7.7" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/river/expert/__init__.py b/river/expert/__init__.py index c867ad3617..d26acba10f 100644 --- a/river/expert/__init__.py +++ b/river/expert/__init__.py @@ -29,9 +29,9 @@ __all__ = [ "EpsilonGreedyRegressor", - 'EWARegressor', + 'EWARegressor', 'SuccessiveHalvingClassifier', 'SuccessiveHalvingRegressor', 'StackingClassifier', 'UCBRegressor', -] \ No newline at end of file +] diff --git a/river/expert/bandit.py b/river/expert/bandit.py index 8665c21981..5fd9c89dea 100644 --- a/river/expert/bandit.py +++ b/river/expert/bandit.py @@ -101,7 +101,7 @@ def learn_one(self, x, y): if self.print_every: if (self._n_iter % self.print_every) == 0: self._print_info() - + if self.save_percentage_pulled: self.store_percentage_pulled += [self.percentage_pulled] @@ -119,7 +119,9 @@ def add_models(self, new_models): self.models += new_models self._n_arms += length_new_models self._N = np.concatenate([self._N, np.zeros(length_new_models, dtype=np.int)]) - self._average_reward = np.concatenate([self._average_reward, np.zeros(length_new_models, dtype=np.float)]) + self._average_reward = np.concatenate( + [self._average_reward, np.zeros(length_new_models, dtype=np.float)] + ) def _compute_scaled_reward(self, y_pred, y_true, update_scaler=True): metric_value = self.metric._eval(y_pred, y_true) @@ -265,4 +267,3 @@ class UCBRegressor(UCBBandit, base.Regressor): def _pred_func(self, model): return model.predict_one - From e128e6153b19c228a351deee0050db4eccc34497 Mon Sep 17 00:00:00 2001 From: Etienne Kintzler Date: Mon, 23 Nov 2020 18:45:42 +0100 Subject: [PATCH 04/14] enumerate all parameters in __init__, fix \epsilon --- river/expert/bandit.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/river/expert/bandit.py b/river/expert/bandit.py index 5fd9c89dea..8876742c06 100644 --- a/river/expert/bandit.py +++ b/river/expert/bandit.py @@ -143,8 +143,11 @@ def _print_info(self): class EpsilonGreedyBandit(Bandit): - def __init__(self, epsilon=0.1, epsilon_decay=None, **kwargs): - super().__init__(**kwargs) + def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transformer, + print_every=None, save_metric_values=False, save_percentage_pulled=False, + epsilon=0.1, epsilon_decay=None): + super().__init__(models=models, metric=metric, reward_scaler=reward_scaler, print_every=print_every, + save_metric_values=save_metric_values, save_percentage_pulled=save_percentage_pulled) self.epsilon = epsilon self.epsilon_decay = epsilon_decay if epsilon_decay: @@ -166,11 +169,11 @@ def _update_arm(self, arm, reward): self.epsilon = self._starting_epsilon*np.exp(-self._n_iter*self.epsilon_decay) -class EpsilonGreedyRegressor(EpsilonGreedyBandit, base.Regressor): +class EpsilonGreedyRegressor(EpsilonGreedyBandit): """Epsilon-greedy bandit algorithm for regression. This bandit selects the best arm (defined as the one with the highest average reward) with - probability $(1 - \epsilon)$ and draws a random arm with probability $\epsilon$. It is also + probability $(1 - \\epsilon)$ and draws a random arm with probability $\\epsilon$. It is also called Follow-The-Leader (FTL) algorithm. For this bandit, reward are supposed to be 1-subgaussian, hence the use of the StandardScaler @@ -208,8 +211,11 @@ def _pred_func(self, model): class UCBBandit(Bandit): - def __init__(self, delta=None, explore_each_arm=1, **kwargs): - super().__init__(**kwargs) + def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transformer, + print_every=None, save_metric_values=False, save_percentage_pulled=False, + delta=None, explore_each_arm=1): + super().__init__(models=models, metric=metric, reward_scaler=reward_scaler, print_every=print_every, + save_metric_values=save_metric_values, save_percentage_pulled=save_percentage_pulled) if delta is not None and (delta >= 1 or delta <= 0): raise ValueError("The parameter delta should be comprised in ]0, 1[ (or set to None)") self.delta = delta From a50693f2ff85769fff22de64270a8f6e2f8a8061 Mon Sep 17 00:00:00 2001 From: Etienne Kintzler Date: Mon, 23 Nov 2020 18:59:22 +0100 Subject: [PATCH 05/14] align on convention: single quote and import --- river/expert/__init__.py | 9 +++------ river/expert/bandit.py | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/river/expert/__init__.py b/river/expert/__init__.py index d26acba10f..ee982a90bc 100644 --- a/river/expert/__init__.py +++ b/river/expert/__init__.py @@ -16,11 +16,8 @@ """ -from .bandit import ( - EpsilonGreedyRegressor, - UCBRegressor, -) - +from .bandit import EpsilonGreedyRegressor +from .bandit import UCBRegressor from .ewa import EWARegressor from .sh import SuccessiveHalvingClassifier from .sh import SuccessiveHalvingRegressor @@ -28,7 +25,7 @@ __all__ = [ - "EpsilonGreedyRegressor", + 'EpsilonGreedyRegressor', 'EWARegressor', 'SuccessiveHalvingClassifier', 'SuccessiveHalvingRegressor', diff --git a/river/expert/bandit.py b/river/expert/bandit.py index 8876742c06..cd1138fd6f 100644 --- a/river/expert/bandit.py +++ b/river/expert/bandit.py @@ -10,7 +10,7 @@ __all__ = [ - "EpsilonGreedyRegressor", + 'EpsilonGreedyRegressor', 'UCBRegressor', ] From 22c792355cad80fac0f04cfc81931c6a09dc1f7e Mon Sep 17 00:00:00 2001 From: Etienne Kintzler Date: Mon, 23 Nov 2020 19:35:19 +0100 Subject: [PATCH 06/14] rm print_every, change print_info->__repr__, skip line after class --- river/expert/bandit.py | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/river/expert/bandit.py b/river/expert/bandit.py index cd1138fd6f..b8f3864f3a 100644 --- a/river/expert/bandit.py +++ b/river/expert/bandit.py @@ -19,8 +19,9 @@ # Determine which object to store (rewards/percentages pulled/loss?) class Bandit(base.EnsembleMixin): + def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transformer, - print_every=None, save_metric_values=False, save_percentage_pulled=False): + save_metric_values=False, save_percentage_pulled=False): if len(models) <= 1: raise ValueError(f"You supply {len(models)} models. At least 2 models should be supplied.") @@ -33,7 +34,6 @@ def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transform super().__init__(models) self.reward_scaler = copy.deepcopy(reward_scaler) self.metric = copy.deepcopy(metric) - self.print_every = print_every self.save_metric_values = save_metric_values if save_metric_values: @@ -49,6 +49,13 @@ def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transform self._N = np.zeros(self._n_arms, dtype=np.int) self._average_reward = np.zeros(self._n_arms, dtype=np.float) + def __repr__(self): + return ( + f"{self.__class__.__name__}" + + f"\n\t{str(self.metric)}" + + f"\n\t{'Best model id: ' + str(self._best_model_idx)}" + ).expandtabs(2) + @abc.abstractmethod def _pull_arm(self): pass @@ -98,10 +105,6 @@ def learn_one(self, x, y): # Specific update of the arm for certain bandit class self._update_arm(chosen_arm, reward) - if self.print_every: - if (self._n_iter % self.print_every) == 0: - self._print_info() - if self.save_percentage_pulled: self.store_percentage_pulled += [self.percentage_pulled] @@ -133,20 +136,13 @@ def _compute_scaled_reward(self, y_pred, y_true, update_scaler=True): reward = self.reward_scaler.transform_one(metric_to_reward_dict)["metric"] return reward - def _print_info(self): - print( - str(self), - str(self.metric), - "Best model id: " + str(self._best_model_idx), - sep="\n\t" - ) - class EpsilonGreedyBandit(Bandit): + def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transformer, - print_every=None, save_metric_values=False, save_percentage_pulled=False, + save_metric_values=False, save_percentage_pulled=False, epsilon=0.1, epsilon_decay=None): - super().__init__(models=models, metric=metric, reward_scaler=reward_scaler, print_every=print_every, + super().__init__(models=models, metric=metric, reward_scaler=reward_scaler, save_metric_values=save_metric_values, save_percentage_pulled=save_percentage_pulled) self.epsilon = epsilon self.epsilon_decay = epsilon_decay @@ -211,10 +207,11 @@ def _pred_func(self, model): class UCBBandit(Bandit): + def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transformer, - print_every=None, save_metric_values=False, save_percentage_pulled=False, + save_metric_values=False, save_percentage_pulled=False, delta=None, explore_each_arm=1): - super().__init__(models=models, metric=metric, reward_scaler=reward_scaler, print_every=print_every, + super().__init__(models=models, metric=metric, reward_scaler=reward_scaler, save_metric_values=save_metric_values, save_percentage_pulled=save_percentage_pulled) if delta is not None and (delta >= 1 or delta <= 0): raise ValueError("The parameter delta should be comprised in ]0, 1[ (or set to None)") From afe1cac7ce56b0abf3a1f757a07ffdf883798d76 Mon Sep 17 00:00:00 2001 From: Etienne Kintzler Date: Mon, 23 Nov 2020 21:36:50 +0100 Subject: [PATCH 07/14] substitute stdlib for numpy --- river/expert/bandit.py | 49 +++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/river/expert/bandit.py b/river/expert/bandit.py index b8f3864f3a..f0cb716e14 100644 --- a/river/expert/bandit.py +++ b/river/expert/bandit.py @@ -1,9 +1,9 @@ import abc import copy +import math +import random import typing -import numpy as np - from river import base from river import metrics from river import preprocessing @@ -18,6 +18,9 @@ # Docstring # Determine which object to store (rewards/percentages pulled/loss?) +def argmax(l): + return max(range(len(l)), key=l.__getitem__) + class Bandit(base.EnsembleMixin): def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transformer, @@ -46,8 +49,8 @@ def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transform # Initializing bandits internals self._n_arms = len(models) self._n_iter = 0 # number of times learn_one is called - self._N = np.zeros(self._n_arms, dtype=np.int) - self._average_reward = np.zeros(self._n_arms, dtype=np.float) + self._N = [0] * self._n_arms + self._average_reward = [0.0] * self._n_arms def __repr__(self): return ( @@ -71,7 +74,7 @@ def _pred_func(self, model): @property def _best_model_idx(self): # average reward instead of cumulated (otherwise favors arms which are pulled often) - return np.argmax(self._average_reward) + return argmax(self._average_reward) @property def best_model(self): @@ -79,7 +82,7 @@ def best_model(self): @property def percentage_pulled(self): - percentages = self._N / sum(self._N) + percentages = [n / sum(self._N) for n in self._N] return percentages def predict_one(self, x): @@ -121,10 +124,8 @@ def add_models(self, new_models): # Careful, not validation of the model is done here (contrary to __init__) self.models += new_models self._n_arms += length_new_models - self._N = np.concatenate([self._N, np.zeros(length_new_models, dtype=np.int)]) - self._average_reward = np.concatenate( - [self._average_reward, np.zeros(length_new_models, dtype=np.float)] - ) + self._N = self._N + [0] * length_new_models + self._average_reward = self._average_reward + [0.0] * length_new_models def _compute_scaled_reward(self, y_pred, y_true, update_scaler=True): metric_value = self.metric._eval(y_pred, y_true) @@ -152,17 +153,17 @@ def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transfor self.reward_scaler = preprocessing.StandardScaler() def _pull_arm(self): - if np.random.rand() > self.epsilon: - chosen_arm = np.argmax(self._average_reward) + if random.random() > self.epsilon: + chosen_arm = argmax(self._average_reward) else: - chosen_arm = np.random.choice(self._n_arms) + chosen_arm = random.choice(range(self._n_arms)) return chosen_arm def _update_arm(self, arm, reward): # The arm internals are already updated in the `learn_one` phase of class `Bandit`. if self.epsilon_decay: - self.epsilon = self._starting_epsilon*np.exp(-self._n_iter*self.epsilon_decay) + self.epsilon = self._starting_epsilon * math.exp(-self._n_iter*self.epsilon_decay) class EpsilonGreedyRegressor(EpsilonGreedyBandit): @@ -222,17 +223,21 @@ def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transfor self.reward_scaler = preprocessing.StandardScaler() def _pull_arm(self): - not_pulled_enough = self._N <= self.explore_each_arm - if any(not_pulled_enough): # Explore all arms pulled less than `explore_each_arm` times - never_pulled_arm = np.where(not_pulled_enough)[0] #[0] because returned a tuple (array(),) even when input is 1D array - chosen_arm = np.random.choice(never_pulled_arm) + # Explore all arms pulled less than `explore_each_arm` times + never_pulled_arm = [i for (i, n) in enumerate(self._N) if n <= self.explore_each_arm] + if never_pulled_arm: + chosen_arm = random.choice(never_pulled_arm) else: if self.delta: - exploration_bonus = np.sqrt(2 * np.log(1/self.delta) / self._N) + exploration_bonus = [math.sqrt(2 * math.log(1/self.delta) / n) for n in self._N] else: - exploration_bonus = np.sqrt(2 * np.log(self._n_iter) / self._N) - upper_bound = self._average_reward + exploration_bonus - chosen_arm = np.argmax(upper_bound) + exploration_bonus = [math.sqrt(2 * math.log(self._n_iter) / n) for n in self._N] + upper_bound = [ + avg_reward + exploration + for (avg_reward, exploration) + in zip(self._average_reward, exploration_bonus) + ] + chosen_arm = argmax(upper_bound) return chosen_arm From 3c25c93002ac643992f4c0ff5e1ad52bd724809b Mon Sep 17 00:00:00 2001 From: Etienne Kintzler Date: Tue, 24 Nov 2020 18:12:12 +0100 Subject: [PATCH 08/14] rm metrics tracing, add _learn_one for powerusers --- river/expert/bandit.py | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/river/expert/bandit.py b/river/expert/bandit.py index f0cb716e14..29aebfbf01 100644 --- a/river/expert/bandit.py +++ b/river/expert/bandit.py @@ -91,6 +91,21 @@ def predict_one(self, x): return y_pred def learn_one(self, x, y): + self._learn_one(x, y) + return self + + def add_models(self, new_models): + if not isinstance(new_models, list): + raise TypeError("Argument `new_models` must be of a list") + + length_new_models = len(new_models) + # Careful, not validation of the model is done here (contrary to __init__) + self.models += new_models + self._n_arms += length_new_models + self._N = self._N + [0] * length_new_models + self._average_reward = self._average_reward + [0.0] * length_new_models + + def _learn_one(self, x, y): chosen_arm = self._pull_arm() chosen_model = self[chosen_arm] @@ -108,24 +123,7 @@ def learn_one(self, x, y): # Specific update of the arm for certain bandit class self._update_arm(chosen_arm, reward) - if self.save_percentage_pulled: - self.store_percentage_pulled += [self.percentage_pulled] - - if self.save_metric_values: - self.metric_values += [self.metric._eval(y_pred, y)] - - return self - - def add_models(self, new_models): - if not isinstance(new_models, list): - raise TypeError("Argument `new_models` must be of a list") - - length_new_models = len(new_models) - # Careful, not validation of the model is done here (contrary to __init__) - self.models += new_models - self._n_arms += length_new_models - self._N = self._N + [0] * length_new_models - self._average_reward = self._average_reward + [0.0] * length_new_models + return self, self.percentage_pulled, self.metric._eval(y_pred, y) def _compute_scaled_reward(self, y_pred, y_true, update_scaler=True): metric_value = self.metric._eval(y_pred, y_true) @@ -233,8 +231,8 @@ def _pull_arm(self): else: exploration_bonus = [math.sqrt(2 * math.log(self._n_iter) / n) for n in self._N] upper_bound = [ - avg_reward + exploration - for (avg_reward, exploration) + avg_reward + exploration + for (avg_reward, exploration) in zip(self._average_reward, exploration_bonus) ] chosen_arm = argmax(upper_bound) From 860e779f287891d6aed182889beaf7b99e4f1045 Mon Sep 17 00:00:00 2001 From: Etienne Kintzler Date: Tue, 24 Nov 2020 18:25:15 +0100 Subject: [PATCH 09/14] forget to rm object tracing in class __init__ signature --- river/expert/bandit.py | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/river/expert/bandit.py b/river/expert/bandit.py index 29aebfbf01..8071966bab 100644 --- a/river/expert/bandit.py +++ b/river/expert/bandit.py @@ -23,8 +23,7 @@ def argmax(l): class Bandit(base.EnsembleMixin): - def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transformer, - save_metric_values=False, save_percentage_pulled=False): + def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transformer): if len(models) <= 1: raise ValueError(f"You supply {len(models)} models. At least 2 models should be supplied.") @@ -38,14 +37,6 @@ def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transform self.reward_scaler = copy.deepcopy(reward_scaler) self.metric = copy.deepcopy(metric) - self.save_metric_values = save_metric_values - if save_metric_values: - self.metric_values: typing.List = [] - - self.save_percentage_pulled = save_percentage_pulled - if save_percentage_pulled: - self.store_percentage_pulled: typing.List = [] - # Initializing bandits internals self._n_arms = len(models) self._n_iter = 0 # number of times learn_one is called @@ -139,10 +130,8 @@ def _compute_scaled_reward(self, y_pred, y_true, update_scaler=True): class EpsilonGreedyBandit(Bandit): def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transformer, - save_metric_values=False, save_percentage_pulled=False, epsilon=0.1, epsilon_decay=None): - super().__init__(models=models, metric=metric, reward_scaler=reward_scaler, - save_metric_values=save_metric_values, save_percentage_pulled=save_percentage_pulled) + super().__init__(models=models, metric=metric, reward_scaler=reward_scaler) self.epsilon = epsilon self.epsilon_decay = epsilon_decay if epsilon_decay: @@ -208,10 +197,8 @@ def _pred_func(self, model): class UCBBandit(Bandit): def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transformer, - save_metric_values=False, save_percentage_pulled=False, delta=None, explore_each_arm=1): - super().__init__(models=models, metric=metric, reward_scaler=reward_scaler, - save_metric_values=save_metric_values, save_percentage_pulled=save_percentage_pulled) + super().__init__(models=models, metric=metric, reward_scaler=reward_scaler) if delta is not None and (delta >= 1 or delta <= 0): raise ValueError("The parameter delta should be comprised in ]0, 1[ (or set to None)") self.delta = delta @@ -270,6 +257,9 @@ class UCBRegressor(UCBBandit, base.Regressor): [^2]: [Lattimore, T., & Szepesvári, C. (2020). Bandit algorithms. Cambridge University Press.](https://tor-lattimore.com/downloads/book/book.pdf) [^3]: [Rivasplata, O. (2012). Subgaussian random variables: An expository note. Internet publication, PDF.]: (https://sites.ualberta.ca/~omarr/publications/subgaussians.pdf) """ + @classmethod + def _default_params(cls): + return {'regressor': linear_model.LogisticRegression()} def _pred_func(self, model): return model.predict_one From 9fe14f1de38e42fbe663f1de848a33bd571507e5 Mon Sep 17 00:00:00 2001 From: Etienne Kintzler Date: Tue, 24 Nov 2020 18:44:03 +0100 Subject: [PATCH 10/14] add type to models, _default_params, use '+=' for list append --- river/expert/bandit.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/river/expert/bandit.py b/river/expert/bandit.py index 8071966bab..190af60b40 100644 --- a/river/expert/bandit.py +++ b/river/expert/bandit.py @@ -5,6 +5,8 @@ import typing from river import base +from river import compose +from river import linear_model from river import metrics from river import preprocessing @@ -16,14 +18,13 @@ # TODO: # Docstring -# Determine which object to store (rewards/percentages pulled/loss?) def argmax(l): return max(range(len(l)), key=l.__getitem__) class Bandit(base.EnsembleMixin): - def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transformer): + def __init__(self, models: typing.List[base.Estimator], metric: metrics.Metric, reward_scaler: base.Transformer): if len(models) <= 1: raise ValueError(f"You supply {len(models)} models. At least 2 models should be supplied.") @@ -85,16 +86,12 @@ def learn_one(self, x, y): self._learn_one(x, y) return self - def add_models(self, new_models): - if not isinstance(new_models, list): - raise TypeError("Argument `new_models` must be of a list") - + def add_models(self, new_models: typing.List[base.Estimator]): length_new_models = len(new_models) - # Careful, not validation of the model is done here (contrary to __init__) self.models += new_models self._n_arms += length_new_models - self._N = self._N + [0] * length_new_models - self._average_reward = self._average_reward + [0.0] * length_new_models + self._N += [0] * length_new_models + self._average_reward += [0.0] * length_new_models def _learn_one(self, x, y): chosen_arm = self._pull_arm() @@ -129,7 +126,7 @@ def _compute_scaled_reward(self, y_pred, y_true, update_scaler=True): class EpsilonGreedyBandit(Bandit): - def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transformer, + def __init__(self, models: typing.List[base.Estimator], metric: metrics.Metric, reward_scaler: base.Transformer, epsilon=0.1, epsilon_decay=None): super().__init__(models=models, metric=metric, reward_scaler=reward_scaler) self.epsilon = epsilon @@ -189,6 +186,12 @@ class EpsilonGreedyRegressor(EpsilonGreedyBandit): [^2]: [Rivasplata, O. (2012). Subgaussian random variables: An expository note. Internet publication, PDF.]: (https://sites.ualberta.ca/~omarr/publications/subgaussians.pdf) [^3]: [Lattimore, T., & Szepesvári, C. (2020). Bandit algorithms. Cambridge University Press.](https://tor-lattimore.com/downloads/book/book.pdf) """ + @classmethod + def _default_params(cls): + return {'regressor': compose.Pipeline( + linear_model.LinearRegression() + )} + def _pred_func(self, model): return model.predict_one @@ -196,7 +199,7 @@ def _pred_func(self, model): class UCBBandit(Bandit): - def __init__(self, models, metric: metrics.Metric, reward_scaler: base.Transformer, + def __init__(self, models: typing.List[base.Estimator], metric: metrics.Metric, reward_scaler: base.Transformer, delta=None, explore_each_arm=1): super().__init__(models=models, metric=metric, reward_scaler=reward_scaler) if delta is not None and (delta >= 1 or delta <= 0): @@ -259,7 +262,9 @@ class UCBRegressor(UCBBandit, base.Regressor): """ @classmethod def _default_params(cls): - return {'regressor': linear_model.LogisticRegression()} + return {'regressor': compose.Pipeline( + linear_model.LinearRegression() + )} def _pred_func(self, model): return model.predict_one From f0b1b6c8cd878a26715f07a00f6bb3729c7bb5eb Mon Sep 17 00:00:00 2001 From: Etienne Kintzler Date: Wed, 25 Nov 2020 09:46:08 +0100 Subject: [PATCH 11/14] change parameters in _default_params --- river/expert/bandit.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/river/expert/bandit.py b/river/expert/bandit.py index 190af60b40..d89f57a7e8 100644 --- a/river/expert/bandit.py +++ b/river/expert/bandit.py @@ -22,6 +22,7 @@ def argmax(l): return max(range(len(l)), key=l.__getitem__) + class Bandit(base.EnsembleMixin): def __init__(self, models: typing.List[base.Estimator], metric: metrics.Metric, reward_scaler: base.Transformer): @@ -187,11 +188,12 @@ class EpsilonGreedyRegressor(EpsilonGreedyBandit): [^3]: [Lattimore, T., & Szepesvári, C. (2020). Bandit algorithms. Cambridge University Press.](https://tor-lattimore.com/downloads/book/book.pdf) """ @classmethod - def _default_params(cls): - return {'regressor': compose.Pipeline( - linear_model.LinearRegression() - )} - + def _default_params(cls): + return { + 'models': [linear_model.LinearRegression(lr=.1), linear_model.LinearRegression(lr=.01)], + 'metric': metrics.MSE(), + 'reward_scaler': preprocessing.StandardScaler() + } def _pred_func(self, model): return model.predict_one @@ -262,9 +264,11 @@ class UCBRegressor(UCBBandit, base.Regressor): """ @classmethod def _default_params(cls): - return {'regressor': compose.Pipeline( - linear_model.LinearRegression() - )} + return { + 'models': [linear_model.LinearRegression(lr=.1), linear_model.LinearRegression(lr=.01)], + 'metric': metrics.MSE(), + 'reward_scaler': preprocessing.StandardScaler() + } def _pred_func(self, model): return model.predict_one From 9cb720cbcfa667f9d3488113a74916fc2ae4c0b4 Mon Sep 17 00:00:00 2001 From: Etienne Kintzler Date: Wed, 25 Nov 2020 09:49:49 +0100 Subject: [PATCH 12/14] intercept_lr instead of lr in LinearRegression --- river/expert/bandit.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/river/expert/bandit.py b/river/expert/bandit.py index d89f57a7e8..29d49cf264 100644 --- a/river/expert/bandit.py +++ b/river/expert/bandit.py @@ -188,9 +188,12 @@ class EpsilonGreedyRegressor(EpsilonGreedyBandit): [^3]: [Lattimore, T., & Szepesvári, C. (2020). Bandit algorithms. Cambridge University Press.](https://tor-lattimore.com/downloads/book/book.pdf) """ @classmethod - def _default_params(cls): + def _default_params(cls): return { - 'models': [linear_model.LinearRegression(lr=.1), linear_model.LinearRegression(lr=.01)], + 'models': [ + linear_model.LinearRegression(intercept_lr=.1), + linear_model.LinearRegression(intercept_lr=.01) + ], 'metric': metrics.MSE(), 'reward_scaler': preprocessing.StandardScaler() } @@ -265,7 +268,10 @@ class UCBRegressor(UCBBandit, base.Regressor): @classmethod def _default_params(cls): return { - 'models': [linear_model.LinearRegression(lr=.1), linear_model.LinearRegression(lr=.01)], + 'models': [ + linear_model.LinearRegression(intercept_lr=.1), + linear_model.LinearRegression(intercept_lr=.01) + ], 'metric': metrics.MSE(), 'reward_scaler': preprocessing.StandardScaler() } From d3169dc07b9b9f0e557cbf229c615df0bfc1fdfc Mon Sep 17 00:00:00 2001 From: Etienne Kintzler Date: Wed, 25 Nov 2020 17:03:31 +0100 Subject: [PATCH 13/14] mv argmax to utils.math --- river/expert/bandit.py | 14 ++++++-------- river/utils/math.py | 12 ++++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/river/expert/bandit.py b/river/expert/bandit.py index 29d49cf264..eacff31e13 100644 --- a/river/expert/bandit.py +++ b/river/expert/bandit.py @@ -5,11 +5,10 @@ import typing from river import base -from river import compose from river import linear_model from river import metrics from river import preprocessing - +from river import utils __all__ = [ 'EpsilonGreedyRegressor', @@ -19,8 +18,7 @@ # TODO: # Docstring -def argmax(l): - return max(range(len(l)), key=l.__getitem__) + class Bandit(base.EnsembleMixin): @@ -67,7 +65,7 @@ def _pred_func(self, model): @property def _best_model_idx(self): # average reward instead of cumulated (otherwise favors arms which are pulled often) - return argmax(self._average_reward) + return utils.math.argmax(self._average_reward) @property def best_model(self): @@ -112,7 +110,7 @@ def _learn_one(self, x, y): # Specific update of the arm for certain bandit class self._update_arm(chosen_arm, reward) - return self, self.percentage_pulled, self.metric._eval(y_pred, y) + return self.metric._eval(y_pred, y) def _compute_scaled_reward(self, y_pred, y_true, update_scaler=True): metric_value = self.metric._eval(y_pred, y_true) @@ -139,7 +137,7 @@ def __init__(self, models: typing.List[base.Estimator], metric: metrics.Metric, def _pull_arm(self): if random.random() > self.epsilon: - chosen_arm = argmax(self._average_reward) + chosen_arm = utils.math.argmax(self._average_reward) else: chosen_arm = random.choice(range(self._n_arms)) @@ -230,7 +228,7 @@ def _pull_arm(self): for (avg_reward, exploration) in zip(self._average_reward, exploration_bonus) ] - chosen_arm = argmax(upper_bound) + chosen_arm = utils.math.argmax(upper_bound) return chosen_arm diff --git a/river/utils/math.py b/river/utils/math.py index 3a08448a58..d8625ddc41 100644 --- a/river/utils/math.py +++ b/river/utils/math.py @@ -12,6 +12,7 @@ __all__ = [ + 'argmax', 'chain_dot', 'clamp', 'dot', @@ -332,3 +333,14 @@ def sign(x: float): """ return -1 if x < 0 else (1 if x > 0 else 0) + + +def argmax(l: list): + """Argmax function. + + Parameters + ---------- + l + + """ + return max(range(len(l)), key=l.__getitem__) From c7b20ca06d547838bfc823d9bba3133aa40e153d Mon Sep 17 00:00:00 2001 From: Etienne Kintzler Date: Wed, 25 Nov 2020 18:29:49 +0100 Subject: [PATCH 14/14] fix mistake: EpsilonGreedyRessor didnt inherit from base.Regressor --- river/expert/bandit.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/river/expert/bandit.py b/river/expert/bandit.py index eacff31e13..e71f8a3422 100644 --- a/river/expert/bandit.py +++ b/river/expert/bandit.py @@ -149,7 +149,7 @@ def _update_arm(self, arm, reward): self.epsilon = self._starting_epsilon * math.exp(-self._n_iter*self.epsilon_decay) -class EpsilonGreedyRegressor(EpsilonGreedyBandit): +class EpsilonGreedyRegressor(EpsilonGreedyBandit, base.Regressor): """Epsilon-greedy bandit algorithm for regression. This bandit selects the best arm (defined as the one with the highest average reward) with @@ -177,7 +177,7 @@ class EpsilonGreedyRegressor(EpsilonGreedyBandit): >>> from river import metrics - TODO: finish ex + TODO: Example References ---------- @@ -256,6 +256,7 @@ class UCBRegressor(UCBBandit, base.Regressor): delta For UCB(delta) implementation. Lower value means more exploration. + TODO: Example References ----------