Improve documentation
This commit is contained in:
parent
51f6f7174b
commit
63a45989f4
40 changed files with 956 additions and 420 deletions
5599
docs/tutorial/data/dev.txt
Normal file
5599
docs/tutorial/data/dev.txt
Normal file
File diff suppressed because it is too large
Load diff
22399
docs/tutorial/data/test.txt
Normal file
22399
docs/tutorial/data/test.txt
Normal file
File diff suppressed because it is too large
Load diff
84000
docs/tutorial/data/train.txt
Normal file
84000
docs/tutorial/data/train.txt
Normal file
File diff suppressed because it is too large
Load diff
214
docs/tutorial/deploy.ipynb
Normal file
214
docs/tutorial/deploy.ipynb
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Harden and deploy your app\n",
|
||||
"\n",
|
||||
"Finally, it's time to deploy your model. But before you have to make sure you follow AI deployment [best-practices](https://se-ml.github.io/). In the past, this step was too often either the source of unexpected struggles, or worse, simply ignored.\n",
|
||||
"\n",
|
||||
"With `GreatAI`, it has become a matter of 2 lines of code."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\u001b[38;5;226m2022-07-09 22:38:56 | WARNING | Environment variable ENVIRONMENT is not set, defaulting to development mode ‼️\u001b[0m\n",
|
||||
"\u001b[38;5;226m2022-07-09 22:38:56 | WARNING | Cannot find credentials files, defaulting to using ParallelTinyDbDriver\u001b[0m\n",
|
||||
"\u001b[38;5;226m2022-07-09 22:38:56 | WARNING | The selected tracing database (ParallelTinyDbDriver) is not recommended for production\u001b[0m\n",
|
||||
"\u001b[38;5;226m2022-07-09 22:38:56 | WARNING | Cannot find credentials files, defaulting to using LargeFileLocal\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:38:56 | INFO | GreatAI (v0.1.0): configured ✅\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:38:56 | INFO | 🔩 tracing_database: ParallelTinyDbDriver\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:38:56 | INFO | 🔩 large_file_implementation: LargeFileLocal\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:38:56 | INFO | 🔩 is_production: False\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:38:56 | INFO | 🔩 should_log_exception_stack: True\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:38:56 | INFO | 🔩 prediction_cache_size: 512\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:38:56 | INFO | 🔩 dashboard_table_size: 20\u001b[0m\n",
|
||||
"\u001b[38;5;226m2022-07-09 22:38:56 | WARNING | You still need to check whether you follow all best practices before trusting your deployment.\u001b[0m\n",
|
||||
"\u001b[38;5;226m2022-07-09 22:38:56 | WARNING | > Find out more at https://se-ml.github.io/practices\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:38:56 | INFO | Fetching cached versions of my-domain-predictor\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:38:56 | INFO | Latest version of my-domain-predictor is 5 (from versions: 0, 1, 2, 3, 4, 5)\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:38:56 | INFO | File my-domain-predictor-5 found in cache\u001b[0m\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from great_ai import GreatAI, use_model\n",
|
||||
"from great_ai.utilities import clean\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"@GreatAI.create\n",
|
||||
"@use_model(\"my-domain-predictor\")\n",
|
||||
"def predict_domain(sentence, model):\n",
|
||||
" inputs = [clean(sentence)]\n",
|
||||
" return str(model.predict(inputs)[0])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Trace[str]({ 'created': '2022-07-09T20:38:56.394746',\n",
|
||||
" 'exception': None,\n",
|
||||
" 'feedback': None,\n",
|
||||
" 'logged_values': { 'arg:sentence:length': 29,\n",
|
||||
" 'arg:sentence:value': 'Mountains are just big rocks.'},\n",
|
||||
" 'models': [{'key': 'my-domain-predictor', 'version': 5}],\n",
|
||||
" 'original_execution_time_ms': 4.999,\n",
|
||||
" 'output': 'geography',\n",
|
||||
" 'tags': ['predict_domain', 'online', 'development'],\n",
|
||||
" 'trace_id': 'aad1f83d-a81f-4b8b-898e-d02f8076616f'})"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"predict_domain(\"Mountains are just big rocks.\")\n",
|
||||
"# the original return value is under the 'output' key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\u001b[38;5;39m2022-07-09 22:38:58 | INFO | Converting notebook to Python script\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:38:58 | INFO | Found `predict_domain` to be the GreatAI app \u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:38:58 | INFO | Uvicorn running on http://0.0.0.0:6060 (Press CTRL+C to quit)\u001b[0m\n",
|
||||
"\u001b[38;5;226m2022-07-09 22:39:00 | WARNING | Environment variable ENVIRONMENT is not set, defaulting to development mode ‼️\u001b[0m\n",
|
||||
"\u001b[38;5;226m2022-07-09 22:39:00 | WARNING | Cannot find credentials files, defaulting to using ParallelTinyDbDriver\u001b[0m\n",
|
||||
"\u001b[38;5;226m2022-07-09 22:39:00 | WARNING | The selected tracing database (ParallelTinyDbDriver) is not recommended for production\u001b[0m\n",
|
||||
"\u001b[38;5;226m2022-07-09 22:39:00 | WARNING | Cannot find credentials files, defaulting to using LargeFileLocal\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:00 | INFO | GreatAI (v0.1.0): configured ✅\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:00 | INFO | 🔩 tracing_database: ParallelTinyDbDriver\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:00 | INFO | 🔩 large_file_implementation: LargeFileLocal\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:00 | INFO | 🔩 is_production: False\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:00 | INFO | 🔩 should_log_exception_stack: True\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:00 | INFO | 🔩 prediction_cache_size: 512\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:00 | INFO | 🔩 dashboard_table_size: 20\u001b[0m\n",
|
||||
"\u001b[38;5;226m2022-07-09 22:39:00 | WARNING | You still need to check whether you follow all best practices before trusting your deployment.\u001b[0m\n",
|
||||
"\u001b[38;5;226m2022-07-09 22:39:00 | WARNING | > Find out more at https://se-ml.github.io/practices\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:00 | INFO | Fetching cached versions of my-domain-predictor\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:00 | INFO | Latest version of my-domain-predictor is 5 (from versions: 0, 1, 2, 3, 4, 5)\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:00 | INFO | File my-domain-predictor-5 found in cache\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:00 | INFO | Started server process [882179]\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:00 | INFO | Waiting for application startup.\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:00 | INFO | Application startup complete.\u001b[0m\n",
|
||||
"^C\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:04 | INFO | Shutting down\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:04 | INFO | Waiting for application shutdown.\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:04 | INFO | Application shutdown complete.\u001b[0m\n",
|
||||
"\u001b[38;5;39m2022-07-09 22:39:04 | INFO | Finished server process [882179]\u001b[0m\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!great-ai deploy.ipynb\n",
|
||||
"# leave this running and open http://127.0.0.1:6060"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now that you've made sure your application is hardened enough for the intended use case, it is time to deploy it. The responsibilities of GreatAI end when it wraps your inference function and model into a production-ready service. You're given the freedom and responsibility to deploy this service. Fortunately, you (or your organisation) probably already has an established routine for deploying services.\n",
|
||||
"\n",
|
||||
"There are three main approaches to deploy a GreatAI service.\n",
|
||||
"\n",
|
||||
"### Manual deployment\n",
|
||||
"\n",
|
||||
"Simply run `ENVIRONMENT=production great-ai deploy.ipynb` in the command-line of a production machine.\n",
|
||||
"> This is the crudest approach, however, it might be fitting for some contexts.\n",
|
||||
"\n",
|
||||
"### Containerised deployment\n",
|
||||
"\n",
|
||||
"Run the notebook directly in a container or create a service for it using your favourite orchestrator.\n",
|
||||
"\n",
|
||||
"```sh\n",
|
||||
"docker run \\\n",
|
||||
" -p 6060:6060 \\\n",
|
||||
" --volume `pwd`:/app \\\n",
|
||||
" --rm \\\n",
|
||||
" schmelczera/great-ai deploy.ipynb\n",
|
||||
"```\n",
|
||||
"> You can replace ``pwd`` with the path to your code's folder.\n",
|
||||
"\n",
|
||||
"#### Use a Platform-as-a-Service\n",
|
||||
"\n",
|
||||
"Similarly to the previous approach, your code will run in a container. However, instead of manually managing it, you can just choose from a plethora of PaaS providers that take a Docker image as a source and handle the rest of the deployment.\n",
|
||||
"\n",
|
||||
"To this end, you can also create a custom Docker image. It is especially useful if you have third-party dependencies, such as pytorch or tensorflow.\n",
|
||||
"\n",
|
||||
"```Dockerfile\n",
|
||||
"FROM schmelczera/great-ai:latest\n",
|
||||
"\n",
|
||||
"# Remove this block if you don't have a requirements.txt\n",
|
||||
"COPY requirements.txt ./ \n",
|
||||
"RUN pip install --no-cache-dir --requirement requirements.txt\n",
|
||||
"\n",
|
||||
"# If you store your models in S3 or GridFS, it may be a \n",
|
||||
"# good idea to # cache them in the image so that you don't\n",
|
||||
"# have to download it each time a container starts\n",
|
||||
"# RUN large-file --backend s3 --secrets s3.ini --cache my-domain-predictor\n",
|
||||
"\n",
|
||||
"COPY . .\n",
|
||||
"\n",
|
||||
"CMD [\"deploy.ipynb\"]\n",
|
||||
"\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### [Go back to the summary](/tutorial)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3.10.4 ('.env': venv)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"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.10.4"
|
||||
},
|
||||
"orig_nbformat": 4,
|
||||
"vscode": {
|
||||
"interpreter": {
|
||||
"hash": "02dd6d3afbfa9fbbe1037d64ad9014965528a1ccad21929d6e72f466389a68ad"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
70
docs/tutorial/index.md
Normal file
70
docs/tutorial/index.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# Train and deploy a SOTA model
|
||||
|
||||
## Overview
|
||||
|
||||
You are going to train a field of study (domain) classifier for scientific sentences. The exact task was proposed by the [SciBERT paper](https://arxiv.org/abs/1903.10676) in which SciBERT [achieved an F1-score of 0.6571](https://paperswithcode.com/sota/sentence-classification-on-paper-field). We are going to outperform it using a trivial text classification model: a [Linear SVM](https://scikit-learn.org/stable/modules/generated/sklearn.svm.LinearSVC.html).
|
||||
|
||||
We use the same synthetic dataset derived from the [Microsoft Academic Graph](https://www.microsoft.com/en-us/research/project/microsoft-academic-graph/). The dataset is [available here](https://github.com/allenai/scibert/tree/master/data/text_classification/mag).
|
||||
|
||||
## Objectives
|
||||
|
||||
1. You will see how the `great_ai.utilities` can integrate into your Data Science workflow.
|
||||
2. You will use `great_ai.large_file` to version and store your trained model
|
||||
3. You will use `GreatAI` to prepare your model for a robust and responsible deployment
|
||||
|
||||
!!! success
|
||||
You are ready to start the tutorial. Feel free to come back to the [summary](#summary) section once you're finished.
|
||||
|
||||
<div style="display: flex; justify-content: space-evenly;" markdown>
|
||||
[:fontawesome-solid-chart-simple: Train it](train.ipynb){ .md-button .md-button--primary }
|
||||
|
||||
[:material-cloud-tags: Deploy it](deploy.ipynb){ .md-button .md-button--secondary }
|
||||
</div>
|
||||
|
||||
|
||||
## Summary
|
||||
|
||||
### The [training notebook](train.ipynb)
|
||||
|
||||
We load and preprocess the dataset while relying on `great_ai.utilities.clean` for the heavy-lifting. Additionally, the preprocessing is parallelised using `great_ai.utilities.simple_parallel_map`.
|
||||
|
||||
After training and evaluating a model, it is exported using `great_ai.save_model`.
|
||||
|
||||
??? tip "Using the cloud"
|
||||
To store your model remotely, you need to set your credentials before calling `save_model`.
|
||||
|
||||
For example, to use [AWS S3](https://aws.amazon.com/s3/):
|
||||
```python
|
||||
from great_ai.large_file import LargeFileS3
|
||||
|
||||
LargeFileS3.configure(
|
||||
aws_region_name='eu-west-2',
|
||||
aws_access_key_id='MY_AWS_ACCESS_KEY',
|
||||
aws_secret_access_key='MY_AWS_SECRET_KEY',
|
||||
large_files_bucket_name='my_bucket_for_models'
|
||||
)
|
||||
|
||||
from great_ai import save_model
|
||||
|
||||
save_model(model, key='my-domain-predictor')
|
||||
```
|
||||
|
||||
### The [deployment notebook](deploy.ipynb)
|
||||
|
||||
We create an inference function that can be hardened by wrapping it in a `great_ai.GreatAI` instance.
|
||||
|
||||
```python
|
||||
from great_ai import GreatAI, use_model
|
||||
from great_ai.utilities import clean
|
||||
|
||||
@GreatAI.create
|
||||
@use_model('my-domain-predictor') #(1)
|
||||
def predict_domain(sentence, model):
|
||||
inputs = [clean(sentence)]
|
||||
return str(model.predict(inputs)[0])
|
||||
```
|
||||
|
||||
1. `@use_model` loads and injects your model into the `predict_domain` function's `model` argument.
|
||||
You can freely reference it knowing that it is always given to the function.
|
||||
|
||||
Finally, we deploy the model, inference function, and the GreatAI wrapping all of these. For that we either use: `great-ai deploy.ipynb` or build a Docker image.
|
||||
318
docs/tutorial/train.ipynb
Normal file
318
docs/tutorial/train.ipynb
Normal file
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue