-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add user docs for Turing/Turing SDK #174
Merged
deadlycoconuts
merged 13 commits into
caraml-dev:main
from
deadlycoconuts:add_user_docs
Mar 17, 2022
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
4665665
Add docs for using pyfunc ensemblers in router deployment
deadlycoconuts 61229c6
Reword pyfunc ensembler section
deadlycoconuts 613d6d4
Add basic user docs for SDK
deadlycoconuts 768b701
Add user docs for SDK classes
deadlycoconuts 16d8a24
Add documentation for ensemblers
deadlycoconuts 71f34a3
Fix typo error in docs
deadlycoconuts 54e80ac
Refactor naming of folders for consistency
deadlycoconuts 3bf2820
Add ensembling request schema to docs
deadlycoconuts 2526846
Edit default readme page
deadlycoconuts 2814f81
Collapse all how-to docs into sample comments
deadlycoconuts c2ac644
Update setup tools
deadlycoconuts 021d5c0
Reword main router docs
deadlycoconuts 3d9a0c9
Fix additional typo erros within the docs
deadlycoconuts File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a new file to demonstrate the deployment of a router with a pyfunc ensembler.