Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 53
Basic Algorithms
Recall that an algorithm consists of 4 basic functions:
initExp: Receive the initial parameters with which to run an experimentgetQuery: Get the next question to askprocessAnswer: Receive an answer to a questiongetModel: Provide its guess for the answer using the information it has received thus far
When we're writing an algorithm,
getQuerywill be the function in which we have the code to cleverly select the next query to ask about (e.g. to maximise the amount of information acquired from the query).processAnswerwill be the function that is called when an answer comes back from the user. In this function, we will store the answer and may possibly perform some computation to help improve our guesses about future classifications.getModelwill return the classifier (appropriately specified) as best we can compute it from the data obtained thus farinitExpwill be called at the start of the experiment.
If a script exists on your own machine that simulates a user responding, it may very roughly look like
## Arguments to all functions very rough; not exact at all# init the algorithm. Set/compute all variablesinitExp()
# the user will answer 100 questionsforninrange(100):
query=getQuery() # ask the user a question. can use all previous queries.reward=random_reward(query) # this is handled by the "app" (e.g., DuelingBandits)processAnswer(reward) # maybe update variables, etc# view the results (in NEXT, this is on the dashboard)getModel()This is how converting simulation code to NEXT code goes; do this step first.
You can use utils.debug_print to print when docker_login'd. This prints in yellow, and optionally any color.
note: use other algorithms inside your app as an example!
The algorithm code is as straightforward as possible, and can simply represent the core mathematical functions that are being tested or compared. This means that:
- algorithms only ever see target indices, not targets (i.e., algorithms receive that user i pulled arm j with reward k -- not that user Apq56avba though "shoe43.png" was "80% chance of purchase"). (this depends on the app developer, but this is the case for the default apps)
- the inputs and outputs are specified exactly in
Algs.yaml(but optional parameters can exist). This means that you only need to make some mapping from inputs to outputs -- NEXT doesn't care how you do it.
Now, there does have to be a layer of code to interface between the relatively unconstrained algorithm code and the NEXT system, but discussed more on Framework-Apps.
In the example launch script (e.g., next/examples/cartoon_dueling), in
alg_list I have the following code (not exact; some names changed):
ifalg_id=='ValidationSampling':
alg_item['params'] = {'num_tries': 15}In myAlg.init, I can call butler.algorithm.get() to get the full list of parameters
I initialized with in the script. i.e., this work: params = butler.algorithms.get()['params'].
The argument checking we use (pijemont) supports many types (dict, str, num, etc). It also supports the types "any", "anything" and "stuff" which mean an arbitrary type. When init'ing the experiment, you can some parameter of type "anything" to Algs.yaml and then include it when launching the experiment in a initExp['args']['alg_list'] item.
Of course, a parameter might not be changed by the user of your algorithm and only by you, the algorithm developer. It's up to you how you want to do this; more defaults in the appropriate functions might be a good call (globals probably aren't a good call).
Every algorithm takes in
- A
butlerobject. Usebutler.algorithms.set(key='foo', value='bar')andbutler.algorithms.get(key='foo)to set/get but more description can be found on Butler-API. - arguments specified in
Algs.yamlas keyword arguments.
Let's see a quick example (we'll do a more in-depth later on this wiki page).
initExp:
args:
n:
description: Number of items the user has to choose from.type: numparams:
description: Possibly algorithm specific parameters.type: anyoptional: truereturns:
type: booldescription: A boolean indicating success.values: truegetQuery:
returns:
type: numdescription: The index of the target we're about to ask aboutprocessAnswer:
args:
reward:
type: numdescription: How much reward the user gave the target (0 or 1)returns:
type: booldescription: A boolean indicating success.values: truegetModel:
returns:
type: dictvalues:
means:
description: The mean score of each targettype: listvalues:
type: numthe corresponding code would look something like below. The following code snippet is meant to highlight
- how arguments and the YAML work together.
- use of the butler. I use butler.algorithms.set and butler.algorithms.get freely and with a list of keys.
classFooAlg:
definitExp(self, butler, n, params):
# setup variables needed later. I can set any value with this.butler.algorithms.set(key='ask_about_this_target', value=42)
returnTruedefgetQuery(self, butler):
# either approach of defining args is acceptable (Python 2.7 allows either)# ...returnbutler.algorithms.get(key='ask_about_this_target')
defprocessAnswer(self, butler, reward):
# I may update variables stored in the butler here# ...returnTruedefgetModel(self, butler):
# when type(key) == list, butler.algorithms.get returns a dictionarydict_=butler.algorithms.get(key=['means', 'precision'])
returndict_['means']