Skip to content

Commit

Permalink
Merge pull request #231 from jklaise/python3-routers
Browse files Browse the repository at this point in the history
Update epsilon-greedy example to Python 3
  • Loading branch information
ukclivecox authored Sep 26, 2018
2 parents 03e3581 + 2d4c786 commit df02555
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 25 deletions.
43 changes: 21 additions & 22 deletions examples/routers/epsilon_greedy/EpsilonGreedy.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import random
import numpy as np

__version__ = "v1.1"
__version__ = "v1.2"

def n_success_failures(features,reward):
n_predictions = features.shape[0]
Expand All @@ -10,9 +10,9 @@ def n_success_failures(features,reward):
return n_success, n_failures

class EpsilonGreedy(object):

def __init__(self,n_branches=None,epsilon=0.1,verbose=False):
print "Starting Epsilon Greedy Microservice, version {}".format(__version__)
print("Starting Epsilon Greedy Microservice, version {}".format(__version__))
if n_branches is None:
raise Exception("n_branches parameter must be given")
self.verbose = verbose
Expand All @@ -22,29 +22,29 @@ def __init__(self,n_branches=None,epsilon=0.1,verbose=False):
self.branches_tries = [0 for _ in range(n_branches)]
self.n_branches = n_branches
if self.verbose:
print "Router initialised"
print "# branches:",self.n_branches
print "Epsilon:",self.epsilon
print
print("Router initialised")
print("# branches:",self.n_branches)
print("Epsilon:",self.epsilon)
print()

def route(self,features,feature_names):
x = random.random()
best_branch = self.best_branch
other_branches = [i for i in range(self.n_branches) if i!=best_branch]
selected_branch = best_branch if x>self.epsilon else random.choice(other_branches)
if self.verbose:
print "Routing"
print "Current best branch:",best_branch
print "Selected branch:",selected_branch
print
print("Routing")
print("Current best branch:",best_branch)
print("Selected branch:",selected_branch)
print()
return selected_branch

def send_feedback(self,features,feature_names,routing,reward,truth):
if self.verbose:
print "Training"
print "Prev success #", self.branches_success
print "Prev tries #", self.branches_tries
print "Prev best branch:", self.best_branch
print("Training")
print("Prev success #", self.branches_success)
print("Prev tries #", self.branches_tries)
print("Prev best branch:", self.best_branch)
n_success, n_failures = n_success_failures(features,reward)
self.branches_success[routing] += n_success
self.branches_tries[routing] += n_success + n_failures
Expand All @@ -55,8 +55,7 @@ def send_feedback(self,features,feature_names,routing,reward,truth):
]
self.best_branch = np.argmax(perfs)
if self.verbose:
print "New success #", self.branches_success
print "New tries #", self.branches_tries
print "New best branch:",self.best_branch
print

print("New success #", self.branches_success)
print("New tries #", self.branches_tries)
print("New best branch:",self.best_branch)
print()
20 changes: 18 additions & 2 deletions examples/routers/epsilon_greedy/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
# Epsilon Greedy Router

## Description

An epsilon-greedy router implements a [multi-armed bandit strategy](https://en.wikipedia.org/wiki/Multi-armed_bandit#Semi-uniform_strategies) in which, when presented with *n* models to make predictions, the currently
best performing model is selected with probability *1-e* while a random model is selected with probability *e*.
This strategy ensures sending traffic to the best performing model most of the time (exploitation) while allowing for
some evaluation of other models (exploration). A typical parameter value could be *e=0.1*, but this will depend on the
desired trade-off between exploration and exploitation.

Note that in this implementation the parameter value *e* is static, but a related strategy called *epsilon-decreasing*
would see the value of *e* decrease as the number of predictions increases, resulting in a highly explorative behaviour
at the start and increasingly exploitative behaviour as time goes on.


## Wrap using s2i

```bash
s2i build . seldonio/seldon-core-s2i-python2 egreedy-router
s2i build . seldonio/seldon-core-s2i-python3 egreedy-router
```

## Smoke Test
Expand All @@ -20,4 +32,8 @@ Send a data request.
```bash
data='{"data":{"names":["a","b"],"ndarray":[[1.0,2.0]]}}'
curl -d "json=${data}" http://0.0.0.0:5000/route
```
```

## Running on Seldon
An end-to-end example deploying an epsilon-greedy router to route traffic to 3 models in parallel is available [here](
https://github.com/SeldonIO/seldon-core/blob/master/notebooks/epsilon_greedy_gcp.ipynb).
2 changes: 1 addition & 1 deletion examples/routers/epsilon_greedy/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
numpy==1.11.2
numpy==1.14.3

0 comments on commit df02555

Please sign in to comment.