-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add user docs for Turing/Turing SDK (#174)
* Add docs for using pyfunc ensemblers in router deployment * Reword pyfunc ensembler section * Add basic user docs for SDK * Add user docs for SDK classes * Add documentation for ensemblers * Fix typo error in docs * Refactor naming of folders for consistency * Add ensembling request schema to docs * Edit default readme page * Collapse all how-to docs into sample comments * Update setup tools * Reword main router docs * Fix additional typo erros within the docs
- Loading branch information
1 parent
0b64559
commit 335efc9
Showing
9 changed files
with
257 additions
and
2 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Introduction | ||
The Turing SDK is a Python tool for interacting with the Turing API, and complements the existing Turing UI available | ||
for managing router creation, deployment, versioning, etc. | ||
|
||
It not only allows you to build your routers in an incremental and configurable manner, it | ||
also gives you the opportunity to write imperative scripts to automate various router modification and deployment | ||
processes, hence simplifying your workflow when interacting with Turing API. | ||
|
||
## What is the Turing SDK? | ||
The Turing SDK is entirely written in Python and acts as a wrapper, around the classes automatically generated (by | ||
[OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator)) from the OpenAPI specs written for the Turing | ||
API. These generated classes in turn act as an intermediary between raw JSON objects that are passed in HTTP | ||
requests/responses made to/received from the Turing API. | ||
|
||
![Turing SDK Classes](https://github.com/gojek/turing/blob/main/sdk/docs/assets/turing-sdk-classes.png?raw=true) | ||
|
||
If you're someone who has used Turing/the Turing UI and would like more control and power over router | ||
management, the Turing SDK fits perfectly for your needs. | ||
|
||
Note that using the Turing SDK assumes that you have basic knowledge of what Turing does and how Turing routers | ||
operate. If you are unsure of these, refer to the Turing UI [docs](https://github.com/gojek/turing/tree/main/docs/how-to) and | ||
familiarise yourself with them first. A list of useful and important concepts used in Turing can also be found | ||
[here](https://github.com/gojek/turing/blob/main/docs/concepts.md). | ||
|
||
Note that some functionalities available with the UI are not available with the Turing SDK, e.g. creating new projects. | ||
|
||
## Samples | ||
Samples of how the Turing SDK can be used to manage routers can be found | ||
[here](https://github.com/gojek/turing/tree/main/sdk/samples). |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
155 changes: 155 additions & 0 deletions
155
sdk/samples/router/create_router_with_pyfunc_ensembler.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
import turing | ||
import turing.batch | ||
import turing.batch.config | ||
import turing.router.config.router_config | ||
from turing.router.config.route import Route | ||
from turing.router.config.router_config import RouterConfig | ||
from turing.router.config.router_version import RouterStatus | ||
from turing.router.config.resource_request import ResourceRequest | ||
from turing.router.config.log_config import LogConfig, ResultLoggerType | ||
from turing.router.config.router_ensembler_config import PyfuncRouterEnsemblerConfig | ||
from turing.router.config.experiment_config import ExperimentConfig | ||
|
||
from typing import List, Any | ||
|
||
|
||
# To register a pyfunc ensembler to be used in a Turing router, implement the `turing.ensembler.PyFunc` interface | ||
class SampleEnsembler(turing.ensembler.PyFunc): | ||
""" | ||
A simple ensembler, that returns the value corresponding to the version that has been specified in the | ||
`features` in each request. This value if obtained from the route responses found in the `predictions` in each | ||
request. | ||
If no version is specified in `features`, return the sum of all the values of all the route responses in | ||
`predictions` instead. | ||
e.g. The values in the route responses (`predictions`) corresponding to the versions, `a`, `b` and `c` are 1, 2 | ||
and 3 respectively. | ||
For a given request, if the version specified in `features` is "a", the ensembler would return the value 1. | ||
If no version is specified in `features`, the ensembler would return the value 6 (1 + 2 + 3). | ||
""" | ||
# `initialize` is essentially a method that gets called when an object of your implemented class gets instantiated | ||
def initialize(self, artifacts: dict): | ||
pass | ||
|
||
# Each time a Turing Router sends a request to a pyfunc ensembler, ensemble will be called, with the request payload | ||
# being passed as the `features` argument, and the route responses as the `predictions` argument. | ||
# | ||
# If an experiment has been set up, the experiment returned would also be passed as the `treatment_config` argument. | ||
# | ||
# The return value of `ensemble` will then be returned as a `json` payload to the Turing router. | ||
def ensemble( | ||
self, | ||
features: dict, | ||
predictions: List[dict], | ||
treatment_config: dict) -> Any: | ||
# Get a mapping between route names and their corresponding responses | ||
routes_to_response = dict() | ||
for prediction in predictions: | ||
routes_to_response[prediction["route"]] = prediction | ||
|
||
if "version" in features: | ||
return routes_to_response[features["version"]]["data"]["value"] | ||
else: | ||
return sum(response["data"]["value"] for response in routes_to_response.values()) | ||
|
||
|
||
def main(turing_api: str, project: str): | ||
# Initialize Turing client | ||
turing.set_url(turing_api) | ||
turing.set_project(project) | ||
|
||
# Register an ensembler with Turing: | ||
ensembler = turing.PyFuncEnsembler.create( | ||
name="sample-ensembler-1", | ||
ensembler_instance=SampleEnsembler(), | ||
conda_env={ | ||
'dependencies': [ | ||
'python>=3.7.0', | ||
# other dependencies, if required | ||
] | ||
} | ||
) | ||
print("Ensembler created:\n", ensembler) | ||
|
||
# Build a router config in order to create a router | ||
# Create some routes | ||
routes = [ | ||
Route( | ||
id='control', | ||
endpoint='http://control.endpoints/predict', | ||
timeout='20ms' | ||
), | ||
Route( | ||
id='experiment-a', | ||
endpoint='http://experiment-a.endpoints/predict', | ||
timeout='20ms' | ||
) | ||
] | ||
|
||
# Create an experiment config ( | ||
experiment_config = ExperimentConfig( | ||
type="nop" | ||
) | ||
|
||
# Create a resource request config for the router | ||
resource_request = ResourceRequest( | ||
min_replica=0, | ||
max_replica=2, | ||
cpu_request="500m", | ||
memory_request="512Mi" | ||
) | ||
|
||
# Create a log config for the router | ||
log_config = LogConfig( | ||
result_logger_type=ResultLoggerType.NOP | ||
) | ||
|
||
# Create an ensembler for the router | ||
ensembler_config = PyfuncRouterEnsemblerConfig( | ||
project_id=1, | ||
ensembler_id=1, | ||
resource_request=ResourceRequest( | ||
min_replica=0, | ||
max_replica=2, | ||
cpu_request="500m", | ||
memory_request="512Mi" | ||
), | ||
timeout="60ms", | ||
) | ||
|
||
# Create the RouterConfig instance | ||
router_config = RouterConfig( | ||
environment_name="id-dev", | ||
name="router-with-pyfunc-ensembler", | ||
routes=routes, | ||
rules=[], | ||
default_route_id="test", | ||
experiment_engine=experiment_config, | ||
resource_request=resource_request, | ||
timeout="100ms", | ||
log_config=log_config, | ||
ensembler=ensembler_config | ||
) | ||
|
||
# Create a new router using the RouterConfig object | ||
new_router = turing.Router.create(router_config) | ||
print(f"You have created a router with id: {new_router.id}") | ||
|
||
# Wait for the router to get deployed | ||
try: | ||
new_router.wait_for_status(RouterStatus.DEPLOYED) | ||
except TimeoutError: | ||
raise Exception(f"Turing API is taking too long for router {new_router.id} to get deployed.") | ||
|
||
# 2. List all routers | ||
routers = turing.Router.list() | ||
for r in routers: | ||
print(r) | ||
|
||
|
||
if __name__ == '__main__': | ||
import fire | ||
fire.Fire(main) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters