mirror of
https://github.com/Azure/MachineLearningNotebooks.git
synced 2025-12-20 01:27:06 -05:00
Compare commits
32 Commits
azureml-sd
...
azureml-sd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8373b93887 | ||
|
|
f0442166cd | ||
|
|
33ca8c7933 | ||
|
|
3fd1ce8993 | ||
|
|
aa93588190 | ||
|
|
12520400e5 | ||
|
|
35614e83fa | ||
|
|
ff22ac01cc | ||
|
|
e7dd826f34 | ||
|
|
fcc882174b | ||
|
|
6872d8a3bb | ||
|
|
a2cb4c3589 | ||
|
|
15008962b2 | ||
|
|
9414b51fac | ||
|
|
80ac414582 | ||
|
|
cbc151660b | ||
|
|
0024abc6e3 | ||
|
|
fa13385860 | ||
|
|
0c5f6daf52 | ||
|
|
c11e9fc1da | ||
|
|
280150713e | ||
|
|
bb11c80b1b | ||
|
|
d0961b98bf | ||
|
|
302589b7f9 | ||
|
|
cc85949d6d | ||
|
|
3a1824e3ad | ||
|
|
579643326d | ||
|
|
14f76f227e | ||
|
|
25baf5203a | ||
|
|
1178fcb0ba | ||
|
|
e4d84c8e45 | ||
|
|
7a3ab1e44c |
@@ -1,6 +1,6 @@
|
|||||||
# Azure Machine Learning Python SDK notebooks
|
# Azure Machine Learning Python SDK notebooks
|
||||||
|
|
||||||
> a community-driven repository of examples using mlflow for tracking can be found at https://github.com/Azure/azureml-examples
|
### **With the introduction of AzureML SDK v2, this samples repository for the v1 SDK is now deprecated and will not be monitored or updated. Users are encouraged to visit the [v2 SDK samples repository](https://github.com/Azure/azureml-examples) instead for up-to-date and enhanced examples of how to build, train, and deploy machine learning models with AzureML's newest features.**
|
||||||
|
|
||||||
Welcome to the Azure Machine Learning Python SDK notebooks repository!
|
Welcome to the Azure Machine Learning Python SDK notebooks repository!
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"import azureml.core\n",
|
"import azureml.core\n",
|
||||||
"\n",
|
"\n",
|
||||||
"print(\"This notebook was created using version 1.49.0 of the Azure ML SDK\")\n",
|
"print(\"This notebook was created using version 1.56.0 of the Azure ML SDK\")\n",
|
||||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -329,7 +329,7 @@
|
|||||||
" print(\"Creating new gpu-cluster\")\n",
|
" print(\"Creating new gpu-cluster\")\n",
|
||||||
" \n",
|
" \n",
|
||||||
" # Specify the configuration for the new cluster\n",
|
" # Specify the configuration for the new cluster\n",
|
||||||
" compute_config = AmlCompute.provisioning_configuration(vm_size=\"STANDARD_NC6\",\n",
|
" compute_config = AmlCompute.provisioning_configuration(vm_size=\"Standard_NC6s_v3\",\n",
|
||||||
" min_nodes=0,\n",
|
" min_nodes=0,\n",
|
||||||
" max_nodes=4)\n",
|
" max_nodes=4)\n",
|
||||||
" # Create the cluster with the specified name and configuration\n",
|
" # Create the cluster with the specified name and configuration\n",
|
||||||
|
|||||||
@@ -174,7 +174,7 @@
|
|||||||
"else:\n",
|
"else:\n",
|
||||||
" print(\"creating new cluster\")\n",
|
" print(\"creating new cluster\")\n",
|
||||||
" # vm_size parameter below could be modified to one of the RAPIDS-supported VM types\n",
|
" # vm_size parameter below could be modified to one of the RAPIDS-supported VM types\n",
|
||||||
" provisioning_config = AmlCompute.provisioning_configuration(vm_size = \"Standard_NC6s_v2\", min_nodes=1, max_nodes = 1)\n",
|
" provisioning_config = AmlCompute.provisioning_configuration(vm_size = \"Standard_NC6s_v3\", min_nodes=1, max_nodes = 1)\n",
|
||||||
"\n",
|
"\n",
|
||||||
" # create the cluster\n",
|
" # create the cluster\n",
|
||||||
" gpu_cluster = ComputeTarget.create(ws, gpu_cluster_name, provisioning_config)\n",
|
" gpu_cluster = ComputeTarget.create(ws, gpu_cluster_name, provisioning_config)\n",
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ dependencies:
|
|||||||
- pip:
|
- pip:
|
||||||
- azureml-sdk
|
- azureml-sdk
|
||||||
- azureml-contrib-fairness
|
- azureml-contrib-fairness
|
||||||
- fairlearn>=0.6.2
|
- fairlearn>=0.6.2,<=0.7.0
|
||||||
- joblib
|
- joblib
|
||||||
- liac-arff
|
- liac-arff
|
||||||
- raiwidgets~=0.24.0
|
- raiwidgets~=0.33.0
|
||||||
- itsdangerous==2.0.1
|
- itsdangerous==2.0.1
|
||||||
- markupsafe<2.1.0
|
- markupsafe<2.1.0
|
||||||
- protobuf==3.20.0
|
- protobuf==3.20.0
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ dependencies:
|
|||||||
- pip:
|
- pip:
|
||||||
- azureml-sdk
|
- azureml-sdk
|
||||||
- azureml-contrib-fairness
|
- azureml-contrib-fairness
|
||||||
- fairlearn>=0.6.2
|
- fairlearn>=0.6.2,<=0.7.0
|
||||||
- joblib
|
- joblib
|
||||||
- liac-arff
|
- liac-arff
|
||||||
- raiwidgets~=0.24.0
|
- raiwidgets~=0.33.0
|
||||||
- itsdangerous==2.0.1
|
- itsdangerous==2.0.1
|
||||||
- markupsafe<2.1.0
|
- markupsafe<2.1.0
|
||||||
- protobuf==3.20.0
|
- protobuf==3.20.0
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ As a pre-requisite, run the [configuration Notebook](../configuration.ipynb) not
|
|||||||
* [train-on-amlcompute](./training/train-on-amlcompute): Use a 1-n node Azure ML managed compute cluster for remote runs on Azure CPU or GPU infrastructure.
|
* [train-on-amlcompute](./training/train-on-amlcompute): Use a 1-n node Azure ML managed compute cluster for remote runs on Azure CPU or GPU infrastructure.
|
||||||
* [train-on-remote-vm](./training/train-on-remote-vm): Use Data Science Virtual Machine as a target for remote runs.
|
* [train-on-remote-vm](./training/train-on-remote-vm): Use Data Science Virtual Machine as a target for remote runs.
|
||||||
* [logging-api](./track-and-monitor-experiments/logging-api): Learn about the details of logging metrics to run history.
|
* [logging-api](./track-and-monitor-experiments/logging-api): Learn about the details of logging metrics to run history.
|
||||||
* [production-deploy-to-aks](./deployment/production-deploy-to-aks) Deploy a model to production at scale on Azure Kubernetes Service.
|
|
||||||
* [enable-app-insights-in-production-service](./deployment/enable-app-insights-in-production-service) Learn how to use App Insights with production web service.
|
* [enable-app-insights-in-production-service](./deployment/enable-app-insights-in-production-service) Learn how to use App Insights with production web service.
|
||||||
|
|
||||||
Find quickstarts, end-to-end tutorials, and how-tos on the [official documentation site for Azure Machine Learning service](https://docs.microsoft.com/en-us/azure/machine-learning/service/).
|
Find quickstarts, end-to-end tutorials, and how-tos on the [official documentation site for Azure Machine Learning service](https://docs.microsoft.com/en-us/azure/machine-learning/service/).
|
||||||
|
|||||||
@@ -5,21 +5,23 @@ channels:
|
|||||||
- main
|
- main
|
||||||
dependencies:
|
dependencies:
|
||||||
# The python interpreter version.
|
# The python interpreter version.
|
||||||
# Azure ML only supports 3.7.0 and later.
|
# Azure ML only supports 3.8 and later.
|
||||||
- pip==22.3.1
|
- pip==22.3.1
|
||||||
- python>=3.7,<3.9
|
- python>=3.10,<3.11
|
||||||
- conda-forge::fbprophet==0.7.1
|
- holidays==0.29
|
||||||
- pandas==1.1.5
|
- scipy==1.10.1
|
||||||
- scipy==1.5.3
|
- tqdm==4.66.1
|
||||||
- Cython==0.29.14
|
|
||||||
- tqdm==4.64.1
|
|
||||||
|
|
||||||
- pip:
|
- pip:
|
||||||
# Required packages for AzureML execution, history, and data preparation.
|
# Required packages for AzureML execution, history, and data preparation.
|
||||||
- azureml-widgets~=1.49.0
|
- azureml-widgets~=1.56.0
|
||||||
- azureml-defaults~=1.49.0
|
- azureml-defaults~=1.56.0
|
||||||
- -r https://automlsdkdataresources.blob.core.windows.net/validated-requirements/1.49.0/validated_win32_requirements.txt [--no-deps]
|
- -r https://automlsdkdataresources.blob.core.windows.net/validated-requirements/1.56.0/validated_win32_requirements.txt [--no-deps]
|
||||||
- matplotlib==3.6.2
|
- matplotlib==3.7.1
|
||||||
- xgboost==1.3.3
|
- xgboost==1.5.2
|
||||||
- cmdstanpy==0.9.5
|
- prophet==1.1.4
|
||||||
|
- pandas==1.3.5
|
||||||
|
- cmdstanpy==1.1.0
|
||||||
- setuptools-git==1.2
|
- setuptools-git==1.2
|
||||||
|
- spacy==3.4.4
|
||||||
|
- https://aka.ms/automl-resources/packages/en_core_web_sm-3.4.1.tar.gz
|
||||||
|
|||||||
@@ -7,26 +7,24 @@ dependencies:
|
|||||||
# The python interpreter version.
|
# The python interpreter version.
|
||||||
# Azure ML only supports 3.7 and later.
|
# Azure ML only supports 3.7 and later.
|
||||||
- pip==22.3.1
|
- pip==22.3.1
|
||||||
- python>=3.7,<3.9
|
- python>=3.10,<3.11
|
||||||
- matplotlib==3.2.1
|
- matplotlib==3.7.1
|
||||||
- numpy>=1.21.6,<=1.22.3
|
- numpy>=1.21.6,<=1.23.5
|
||||||
- cython==0.29.14
|
|
||||||
- urllib3==1.26.7
|
- urllib3==1.26.7
|
||||||
- scipy>=1.4.1,<=1.5.3
|
- scipy==1.10.1
|
||||||
- scikit-learn==0.22.1
|
- scikit-learn==1.1.3
|
||||||
- py-xgboost<=1.3.3
|
- holidays==0.29
|
||||||
- holidays==0.10.3
|
|
||||||
- conda-forge::fbprophet==0.7.1
|
|
||||||
- pytorch::pytorch=1.11.0
|
- pytorch::pytorch=1.11.0
|
||||||
- cudatoolkit=10.1.243
|
- cudatoolkit=10.1.243
|
||||||
- notebook
|
- notebook
|
||||||
|
|
||||||
- pip:
|
- pip:
|
||||||
# Required packages for AzureML execution, history, and data preparation.
|
# Required packages for AzureML execution, history, and data preparation.
|
||||||
- azureml-widgets~=1.49.0
|
- azureml-widgets~=1.56.0
|
||||||
- azureml-defaults~=1.49.0
|
- azureml-defaults~=1.56.0
|
||||||
- pytorch-transformers==1.0.0
|
- pytorch-transformers==1.0.0
|
||||||
- spacy==2.2.4
|
- spacy==3.4.4
|
||||||
- pystan==2.19.1.1
|
- xgboost==1.5.2
|
||||||
- https://aka.ms/automl-resources/packages/en_core_web_sm-2.1.0.tar.gz
|
- prophet==1.1.4
|
||||||
- -r https://automlsdkdataresources.blob.core.windows.net/validated-requirements/1.49.0/validated_linux_requirements.txt [--no-deps]
|
- https://aka.ms/automl-resources/packages/en_core_web_sm-3.4.1.tar.gz
|
||||||
|
- -r https://automlsdkdataresources.blob.core.windows.net/validated-requirements/1.56.0/validated_linux_requirements.txt [--no-deps]
|
||||||
|
|||||||
@@ -7,26 +7,20 @@ dependencies:
|
|||||||
# The python interpreter version.
|
# The python interpreter version.
|
||||||
# Currently Azure ML only supports 3.7 and later.
|
# Currently Azure ML only supports 3.7 and later.
|
||||||
- pip==22.3.1
|
- pip==22.3.1
|
||||||
- python>=3.7,<3.9
|
- python>=3.10,<3.11
|
||||||
- matplotlib==3.2.1
|
- numpy>=1.21.6,<=1.23.5
|
||||||
- numpy>=1.21.6,<=1.22.3
|
- scipy==1.10.1
|
||||||
- cython==0.29.14
|
- scikit-learn==1.1.3
|
||||||
- urllib3==1.26.7
|
- holidays==0.29
|
||||||
- scipy>=1.4.1,<=1.5.3
|
|
||||||
- scikit-learn==0.22.1
|
|
||||||
- py-xgboost<=1.3.3
|
|
||||||
- holidays==0.10.3
|
|
||||||
- conda-forge::fbprophet==0.7.1
|
|
||||||
- pytorch::pytorch=1.11.0
|
|
||||||
- cudatoolkit=9.0
|
|
||||||
- notebook
|
|
||||||
|
|
||||||
- pip:
|
- pip:
|
||||||
# Required packages for AzureML execution, history, and data preparation.
|
# Required packages for AzureML execution, history, and data preparation.
|
||||||
- azureml-widgets~=1.49.0
|
- azureml-widgets~=1.56.0
|
||||||
- azureml-defaults~=1.49.0
|
- azureml-defaults~=1.56.0
|
||||||
- pytorch-transformers==1.0.0
|
- pytorch-transformers==1.0.0
|
||||||
- spacy==2.2.4
|
- prophet==1.1.4
|
||||||
- pystan==2.19.1.1
|
- xgboost==1.5.2
|
||||||
- https://aka.ms/automl-resources/packages/en_core_web_sm-2.1.0.tar.gz
|
- spacy==3.4.4
|
||||||
- -r https://automlsdkdataresources.blob.core.windows.net/validated-requirements/1.49.0/validated_darwin_requirements.txt [--no-deps]
|
- matplotlib==3.7.1
|
||||||
|
- https://aka.ms/automl-resources/packages/en_core_web_sm-3.4.1.tar.gz
|
||||||
|
- -r https://automlsdkdataresources.blob.core.windows.net/validated-requirements/1.56.0/validated_darwin_requirements.txt [--no-deps]
|
||||||
|
|||||||
@@ -1,5 +1,21 @@
|
|||||||
{
|
{
|
||||||
"cells": [
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
||||||
|
"\n",
|
||||||
|
"Licensed under the MIT License."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
@@ -712,7 +728,9 @@
|
|||||||
"from azureml.core.model import Model\n",
|
"from azureml.core.model import Model\n",
|
||||||
"from azureml.core.environment import Environment\n",
|
"from azureml.core.environment import Environment\n",
|
||||||
"\n",
|
"\n",
|
||||||
"inference_config = InferenceConfig(entry_script=script_file_name)\n",
|
"inference_config = InferenceConfig(\n",
|
||||||
|
" environment=best_run.get_environment(), entry_script=script_file_name\n",
|
||||||
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"aciconfig = AciWebservice.deploy_configuration(\n",
|
"aciconfig = AciWebservice.deploy_configuration(\n",
|
||||||
" cpu_cores=2,\n",
|
" cpu_cores=2,\n",
|
||||||
@@ -828,9 +846,7 @@
|
|||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": null,
|
||||||
"metadata": {
|
"metadata": {},
|
||||||
"scrolled": true
|
|
||||||
},
|
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"%matplotlib notebook\n",
|
"%matplotlib notebook\n",
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-classification-bank-marketing-all-features
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -1,5 +1,21 @@
|
|||||||
{
|
{
|
||||||
"cells": [
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
||||||
|
"\n",
|
||||||
|
"Licensed under the MIT License."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-classification-credit-card-fraud
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -1,593 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Automated Machine Learning\n",
|
|
||||||
"_**Text Classification Using Deep Learning**_\n",
|
|
||||||
"\n",
|
|
||||||
"## Contents\n",
|
|
||||||
"1. [Introduction](#Introduction)\n",
|
|
||||||
"1. [Setup](#Setup)\n",
|
|
||||||
"1. [Data](#Data)\n",
|
|
||||||
"1. [Train](#Train)\n",
|
|
||||||
"1. [Evaluate](#Evaluate)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Introduction\n",
|
|
||||||
"This notebook demonstrates classification with text data using deep learning in AutoML.\n",
|
|
||||||
"\n",
|
|
||||||
"AutoML highlights here include using deep neural networks (DNNs) to create embedded features from text data. Depending on the compute cluster the user provides, AutoML tried out Bidirectional Encoder Representations from Transformers (BERT) when a GPU compute is used, and Bidirectional Long-Short Term neural network (BiLSTM) when a CPU compute is used, thereby optimizing the choice of DNN for the uesr's setup.\n",
|
|
||||||
"\n",
|
|
||||||
"Make sure you have executed the [configuration](../../../configuration.ipynb) before running this notebook.\n",
|
|
||||||
"\n",
|
|
||||||
"Notebook synopsis:\n",
|
|
||||||
"\n",
|
|
||||||
"1. Creating an Experiment in an existing Workspace\n",
|
|
||||||
"2. Configuration and remote run of AutoML for a text dataset (20 Newsgroups dataset from scikit-learn) for classification\n",
|
|
||||||
"3. Registering the best model for future use\n",
|
|
||||||
"4. Evaluating the final model on a test set"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Setup"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import json\n",
|
|
||||||
"import logging\n",
|
|
||||||
"import os\n",
|
|
||||||
"import shutil\n",
|
|
||||||
"\n",
|
|
||||||
"import pandas as pd\n",
|
|
||||||
"\n",
|
|
||||||
"import azureml.core\n",
|
|
||||||
"from azureml.core.experiment import Experiment\n",
|
|
||||||
"from azureml.core.workspace import Workspace\n",
|
|
||||||
"from azureml.core.dataset import Dataset\n",
|
|
||||||
"from azureml.core.compute import AmlCompute\n",
|
|
||||||
"from azureml.core.compute import ComputeTarget\n",
|
|
||||||
"from azureml.core.run import Run\n",
|
|
||||||
"from azureml.widgets import RunDetails\n",
|
|
||||||
"from azureml.core.model import Model\n",
|
|
||||||
"from helper import run_inference, get_result_df\n",
|
|
||||||
"from azureml.train.automl import AutoMLConfig\n",
|
|
||||||
"from sklearn.datasets import fetch_20newsgroups"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"This sample notebook may use features that are not available in previous versions of the Azure ML SDK."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"As part of the setup you have already created a <b>Workspace</b>. To run AutoML, you also need to create an <b>Experiment</b>. An Experiment corresponds to a prediction problem you are trying to solve, while a Run corresponds to a specific approach to the problem."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"ws = Workspace.from_config()\n",
|
|
||||||
"\n",
|
|
||||||
"# Choose an experiment name.\n",
|
|
||||||
"experiment_name = \"automl-classification-text-dnn\"\n",
|
|
||||||
"\n",
|
|
||||||
"experiment = Experiment(ws, experiment_name)\n",
|
|
||||||
"\n",
|
|
||||||
"output = {}\n",
|
|
||||||
"output[\"Subscription ID\"] = ws.subscription_id\n",
|
|
||||||
"output[\"Workspace Name\"] = ws.name\n",
|
|
||||||
"output[\"Resource Group\"] = ws.resource_group\n",
|
|
||||||
"output[\"Location\"] = ws.location\n",
|
|
||||||
"output[\"Experiment Name\"] = experiment.name\n",
|
|
||||||
"output[\"SDK Version\"] = azureml.core.VERSION\n",
|
|
||||||
"pd.set_option(\"display.max_colwidth\", None)\n",
|
|
||||||
"outputDf = pd.DataFrame(data=output, index=[\"\"])\n",
|
|
||||||
"outputDf.T"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Set up a compute cluster\n",
|
|
||||||
"This section uses a user-provided compute cluster (named \"dnntext-cluster\" in this example). If a cluster with this name does not exist in the user's workspace, the below code will create a new cluster. You can choose the parameters of the cluster as mentioned in the comments.\n",
|
|
||||||
"\n",
|
|
||||||
"> Note that if you have an AzureML Data Scientist role, you will not have permission to create compute resources. Talk to your workspace or IT admin to create the compute targets described in this section, if they do not already exist.\n",
|
|
||||||
"\n",
|
|
||||||
"Whether you provide/select a CPU or GPU cluster, AutoML will choose the appropriate DNN for that setup - BiLSTM or BERT text featurizer will be included in the candidate featurizers on CPU and GPU respectively. If your goal is to obtain the most accurate model, we recommend you use GPU clusters since BERT featurizers usually outperform BiLSTM featurizers."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.compute import ComputeTarget, AmlCompute\n",
|
|
||||||
"from azureml.core.compute_target import ComputeTargetException\n",
|
|
||||||
"\n",
|
|
||||||
"num_nodes = 2\n",
|
|
||||||
"\n",
|
|
||||||
"# Choose a name for your cluster.\n",
|
|
||||||
"amlcompute_cluster_name = \"dnntext-cluster\"\n",
|
|
||||||
"\n",
|
|
||||||
"# Verify that cluster does not exist already\n",
|
|
||||||
"try:\n",
|
|
||||||
" compute_target = ComputeTarget(workspace=ws, name=amlcompute_cluster_name)\n",
|
|
||||||
" print(\"Found existing cluster, use it.\")\n",
|
|
||||||
"except ComputeTargetException:\n",
|
|
||||||
" compute_config = AmlCompute.provisioning_configuration(\n",
|
|
||||||
" vm_size=\"STANDARD_NC6\", # CPU for BiLSTM, such as \"STANDARD_D2_V2\"\n",
|
|
||||||
" # To use BERT (this is recommended for best performance), select a GPU such as \"STANDARD_NC6\"\n",
|
|
||||||
" # or similar GPU option\n",
|
|
||||||
" # available in your workspace\n",
|
|
||||||
" idle_seconds_before_scaledown=60,\n",
|
|
||||||
" max_nodes=num_nodes,\n",
|
|
||||||
" )\n",
|
|
||||||
" compute_target = ComputeTarget.create(ws, amlcompute_cluster_name, compute_config)\n",
|
|
||||||
"\n",
|
|
||||||
"compute_target.wait_for_completion(show_output=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Get data\n",
|
|
||||||
"For this notebook we will use 20 Newsgroups data from scikit-learn. We filter the data to contain four classes and take a sample as training data. Please note that for accuracy improvement, more data is needed. For this notebook we provide a small-data example so that you can use this template to use with your larger sized data."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"data_dir = \"text-dnn-data\" # Local directory to store data\n",
|
|
||||||
"blobstore_datadir = data_dir # Blob store directory to store data in\n",
|
|
||||||
"target_column_name = \"y\"\n",
|
|
||||||
"feature_column_name = \"X\"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def get_20newsgroups_data():\n",
|
|
||||||
" \"\"\"Fetches 20 Newsgroups data from scikit-learn\n",
|
|
||||||
" Returns them in form of pandas dataframes\n",
|
|
||||||
" \"\"\"\n",
|
|
||||||
" remove = (\"headers\", \"footers\", \"quotes\")\n",
|
|
||||||
" categories = [\n",
|
|
||||||
" \"rec.sport.baseball\",\n",
|
|
||||||
" \"rec.sport.hockey\",\n",
|
|
||||||
" \"comp.graphics\",\n",
|
|
||||||
" \"sci.space\",\n",
|
|
||||||
" ]\n",
|
|
||||||
"\n",
|
|
||||||
" data = fetch_20newsgroups(\n",
|
|
||||||
" subset=\"train\",\n",
|
|
||||||
" categories=categories,\n",
|
|
||||||
" shuffle=True,\n",
|
|
||||||
" random_state=42,\n",
|
|
||||||
" remove=remove,\n",
|
|
||||||
" )\n",
|
|
||||||
" data = pd.DataFrame(\n",
|
|
||||||
" {feature_column_name: data.data, target_column_name: data.target}\n",
|
|
||||||
" )\n",
|
|
||||||
"\n",
|
|
||||||
" data_train = data[:200]\n",
|
|
||||||
" data_test = data[200:300]\n",
|
|
||||||
"\n",
|
|
||||||
" data_train = remove_blanks_20news(\n",
|
|
||||||
" data_train, feature_column_name, target_column_name\n",
|
|
||||||
" )\n",
|
|
||||||
" data_test = remove_blanks_20news(data_test, feature_column_name, target_column_name)\n",
|
|
||||||
"\n",
|
|
||||||
" return data_train, data_test\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def remove_blanks_20news(data, feature_column_name, target_column_name):\n",
|
|
||||||
"\n",
|
|
||||||
" for index, row in data.iterrows():\n",
|
|
||||||
" data.at[index, feature_column_name] = (\n",
|
|
||||||
" row[feature_column_name].replace(\"\\n\", \" \").strip()\n",
|
|
||||||
" )\n",
|
|
||||||
"\n",
|
|
||||||
" data = data[data[feature_column_name] != \"\"]\n",
|
|
||||||
"\n",
|
|
||||||
" return data"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Fetch data and upload to datastore for use in training"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"data_train, data_test = get_20newsgroups_data()\n",
|
|
||||||
"\n",
|
|
||||||
"if not os.path.isdir(data_dir):\n",
|
|
||||||
" os.mkdir(data_dir)\n",
|
|
||||||
"\n",
|
|
||||||
"train_data_fname = data_dir + \"/train_data.csv\"\n",
|
|
||||||
"test_data_fname = data_dir + \"/test_data.csv\"\n",
|
|
||||||
"\n",
|
|
||||||
"data_train.to_csv(train_data_fname, index=False)\n",
|
|
||||||
"data_test.to_csv(test_data_fname, index=False)\n",
|
|
||||||
"\n",
|
|
||||||
"datastore = ws.get_default_datastore()\n",
|
|
||||||
"datastore.upload(src_dir=data_dir, target_path=blobstore_datadir, overwrite=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"train_dataset = Dataset.Tabular.from_delimited_files(\n",
|
|
||||||
" path=[(datastore, blobstore_datadir + \"/train_data.csv\")]\n",
|
|
||||||
")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Prepare AutoML run"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"This notebook uses the blocked_models parameter to exclude some models that can take a longer time to train on some text datasets. You can choose to remove models from the blocked_models list but you may need to increase the experiment_timeout_hours parameter value to get results."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"automl_settings = {\n",
|
|
||||||
" \"experiment_timeout_minutes\": 30,\n",
|
|
||||||
" \"primary_metric\": \"accuracy\",\n",
|
|
||||||
" \"max_concurrent_iterations\": num_nodes,\n",
|
|
||||||
" \"max_cores_per_iteration\": -1,\n",
|
|
||||||
" \"enable_dnn\": True,\n",
|
|
||||||
" \"enable_early_stopping\": True,\n",
|
|
||||||
" \"validation_size\": 0.3,\n",
|
|
||||||
" \"verbosity\": logging.INFO,\n",
|
|
||||||
" \"enable_voting_ensemble\": False,\n",
|
|
||||||
" \"enable_stack_ensemble\": False,\n",
|
|
||||||
"}\n",
|
|
||||||
"\n",
|
|
||||||
"automl_config = AutoMLConfig(\n",
|
|
||||||
" task=\"classification\",\n",
|
|
||||||
" debug_log=\"automl_errors.log\",\n",
|
|
||||||
" compute_target=compute_target,\n",
|
|
||||||
" training_data=train_dataset,\n",
|
|
||||||
" label_column_name=target_column_name,\n",
|
|
||||||
" blocked_models=[\"LightGBM\", \"XGBoostClassifier\"],\n",
|
|
||||||
" **automl_settings,\n",
|
|
||||||
")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Submit AutoML Run"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"automl_run = experiment.submit(automl_config, show_output=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Displaying the run objects gives you links to the visual tools in the Azure Portal. Go try them!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Retrieve the Best Model\n",
|
|
||||||
"Below we select the best model pipeline from our iterations, use it to test on test data on the same compute cluster."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"For local inferencing, you can load the model locally via. the method `remote_run.get_output()`. For more information on the arguments expected by this method, you can run `remote_run.get_output??`.\n",
|
|
||||||
"Note that when the model contains BERT, this step will require pytorch and pytorch-transformers installed in your local environment. The exact versions of these packages can be found in the **automl_env.yml** file located in the local copy of your azureml-examples folder here: \"azureml-examples/python-sdk/tutorials/automl-with-azureml\""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Retrieve the best Run object\n",
|
|
||||||
"best_run = automl_run.get_best_child()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"You can now see what text transformations are used to convert text data to features for this dataset, including deep learning transformations based on BiLSTM or Transformer (BERT is one implementation of a Transformer) models."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Download the featurization summary JSON file locally\n",
|
|
||||||
"best_run.download_file(\n",
|
|
||||||
" \"outputs/featurization_summary.json\", \"featurization_summary.json\"\n",
|
|
||||||
")\n",
|
|
||||||
"\n",
|
|
||||||
"# Render the JSON as a pandas DataFrame\n",
|
|
||||||
"with open(\"featurization_summary.json\", \"r\") as f:\n",
|
|
||||||
" records = json.load(f)\n",
|
|
||||||
"\n",
|
|
||||||
"featurization_summary = pd.DataFrame.from_records(records)\n",
|
|
||||||
"featurization_summary[\"Transformations\"].tolist()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Registering the best model\n",
|
|
||||||
"We now register the best fitted model from the AutoML Run for use in future deployments. "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Get results stats, extract the best model from AutoML run, download and register the resultant best model"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"summary_df = get_result_df(automl_run)\n",
|
|
||||||
"best_dnn_run_id = summary_df[\"run_id\"].iloc[0]\n",
|
|
||||||
"best_dnn_run = Run(experiment, best_dnn_run_id)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"model_dir = \"Model\" # Local folder where the model will be stored temporarily\n",
|
|
||||||
"if not os.path.isdir(model_dir):\n",
|
|
||||||
" os.mkdir(model_dir)\n",
|
|
||||||
"\n",
|
|
||||||
"best_dnn_run.download_file(\"outputs/model.pkl\", model_dir + \"/model.pkl\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Register the model in your Azure Machine Learning Workspace. If you previously registered a model, please make sure to delete it so as to replace it with this new model."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Register the model\n",
|
|
||||||
"model_name = \"textDNN-20News\"\n",
|
|
||||||
"model = Model.register(\n",
|
|
||||||
" model_path=model_dir + \"/model.pkl\", model_name=model_name, tags=None, workspace=ws\n",
|
|
||||||
")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Evaluate on Test Data"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"We now use the best fitted model from the AutoML Run to make predictions on the test set. \n",
|
|
||||||
"\n",
|
|
||||||
"Test set schema should match that of the training set."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"test_dataset = Dataset.Tabular.from_delimited_files(\n",
|
|
||||||
" path=[(datastore, blobstore_datadir + \"/test_data.csv\")]\n",
|
|
||||||
")\n",
|
|
||||||
"\n",
|
|
||||||
"# preview the first 3 rows of the dataset\n",
|
|
||||||
"test_dataset.take(3).to_pandas_dataframe()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"test_experiment = Experiment(ws, experiment_name + \"_test\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"script_folder = os.path.join(os.getcwd(), \"inference\")\n",
|
|
||||||
"os.makedirs(script_folder, exist_ok=True)\n",
|
|
||||||
"shutil.copy(\"infer.py\", script_folder)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"test_run = run_inference(\n",
|
|
||||||
" test_experiment,\n",
|
|
||||||
" compute_target,\n",
|
|
||||||
" script_folder,\n",
|
|
||||||
" best_dnn_run,\n",
|
|
||||||
" test_dataset,\n",
|
|
||||||
" target_column_name,\n",
|
|
||||||
" model_name,\n",
|
|
||||||
")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Display computed metrics"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"test_run"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"RunDetails(test_run).show()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"test_run.wait_for_completion()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"pd.Series(test_run.get_metrics())"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "anshirga"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"compute": [
|
|
||||||
"AML Compute"
|
|
||||||
],
|
|
||||||
"datasets": [
|
|
||||||
"None"
|
|
||||||
],
|
|
||||||
"deployment": [
|
|
||||||
"None"
|
|
||||||
],
|
|
||||||
"exclude_from_index": false,
|
|
||||||
"framework": [
|
|
||||||
"None"
|
|
||||||
],
|
|
||||||
"friendly_name": "DNN Text Featurization",
|
|
||||||
"index_order": 2,
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3.8 - AzureML",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python38-azureml"
|
|
||||||
},
|
|
||||||
"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.6.7"
|
|
||||||
},
|
|
||||||
"tags": [
|
|
||||||
"None"
|
|
||||||
],
|
|
||||||
"task": "Text featurization using DNNs for classification"
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-classification-text-dnn
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
import pandas as pd
|
|
||||||
from azureml.core import Environment, ScriptRunConfig
|
|
||||||
from azureml.core.run import Run
|
|
||||||
|
|
||||||
|
|
||||||
def run_inference(
|
|
||||||
test_experiment,
|
|
||||||
compute_target,
|
|
||||||
script_folder,
|
|
||||||
train_run,
|
|
||||||
test_dataset,
|
|
||||||
target_column_name,
|
|
||||||
model_name,
|
|
||||||
):
|
|
||||||
|
|
||||||
inference_env = train_run.get_environment()
|
|
||||||
|
|
||||||
est = ScriptRunConfig(
|
|
||||||
source_directory=script_folder,
|
|
||||||
script="infer.py",
|
|
||||||
arguments=[
|
|
||||||
"--target_column_name",
|
|
||||||
target_column_name,
|
|
||||||
"--model_name",
|
|
||||||
model_name,
|
|
||||||
"--input-data",
|
|
||||||
test_dataset.as_named_input("data"),
|
|
||||||
],
|
|
||||||
compute_target=compute_target,
|
|
||||||
environment=inference_env,
|
|
||||||
)
|
|
||||||
|
|
||||||
run = test_experiment.submit(
|
|
||||||
est,
|
|
||||||
tags={
|
|
||||||
"training_run_id": train_run.id,
|
|
||||||
"run_algorithm": train_run.properties["run_algorithm"],
|
|
||||||
"valid_score": train_run.properties["score"],
|
|
||||||
"primary_metric": train_run.properties["primary_metric"],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
run.log("run_algorithm", run.tags["run_algorithm"])
|
|
||||||
return run
|
|
||||||
|
|
||||||
|
|
||||||
def get_result_df(remote_run):
|
|
||||||
|
|
||||||
children = list(remote_run.get_children(recursive=True))
|
|
||||||
summary_df = pd.DataFrame(
|
|
||||||
index=["run_id", "run_algorithm", "primary_metric", "Score"]
|
|
||||||
)
|
|
||||||
goal_minimize = False
|
|
||||||
for run in children:
|
|
||||||
if "run_algorithm" in run.properties and "score" in run.properties:
|
|
||||||
summary_df[run.id] = [
|
|
||||||
run.id,
|
|
||||||
run.properties["run_algorithm"],
|
|
||||||
run.properties["primary_metric"],
|
|
||||||
float(run.properties["score"]),
|
|
||||||
]
|
|
||||||
if "goal" in run.properties:
|
|
||||||
goal_minimize = run.properties["goal"].split("_")[-1] == "min"
|
|
||||||
|
|
||||||
summary_df = summary_df.T.sort_values(
|
|
||||||
"Score", ascending=goal_minimize
|
|
||||||
).drop_duplicates(["run_algorithm"])
|
|
||||||
summary_df = summary_df.set_index("run_algorithm")
|
|
||||||
|
|
||||||
return summary_df
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
import argparse
|
|
||||||
|
|
||||||
import pandas as pd
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
from sklearn.externals import joblib
|
|
||||||
|
|
||||||
from azureml.automl.runtime.shared.score import scoring, constants
|
|
||||||
from azureml.core import Run, Dataset
|
|
||||||
from azureml.core.model import Model
|
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument(
|
|
||||||
"--target_column_name",
|
|
||||||
type=str,
|
|
||||||
dest="target_column_name",
|
|
||||||
help="Target Column Name",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--model_name", type=str, dest="model_name", help="Name of registered model"
|
|
||||||
)
|
|
||||||
|
|
||||||
parser.add_argument("--input-data", type=str, dest="input_data", help="Dataset")
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
target_column_name = args.target_column_name
|
|
||||||
model_name = args.model_name
|
|
||||||
|
|
||||||
print("args passed are: ")
|
|
||||||
print("Target column name: ", target_column_name)
|
|
||||||
print("Name of registered model: ", model_name)
|
|
||||||
|
|
||||||
model_path = Model.get_model_path(model_name)
|
|
||||||
# deserialize the model file back into a sklearn model
|
|
||||||
model = joblib.load(model_path)
|
|
||||||
|
|
||||||
run = Run.get_context()
|
|
||||||
|
|
||||||
test_dataset = Dataset.get_by_id(run.experiment.workspace, id=args.input_data)
|
|
||||||
|
|
||||||
X_test_df = test_dataset.drop_columns(
|
|
||||||
columns=[target_column_name]
|
|
||||||
).to_pandas_dataframe()
|
|
||||||
y_test_df = (
|
|
||||||
test_dataset.with_timestamp_columns(None)
|
|
||||||
.keep_columns(columns=[target_column_name])
|
|
||||||
.to_pandas_dataframe()
|
|
||||||
)
|
|
||||||
|
|
||||||
predicted = model.predict_proba(X_test_df)
|
|
||||||
|
|
||||||
if isinstance(predicted, pd.DataFrame):
|
|
||||||
predicted = predicted.values
|
|
||||||
|
|
||||||
# Use the AutoML scoring module
|
|
||||||
train_labels = model.classes_
|
|
||||||
class_labels = np.unique(
|
|
||||||
np.concatenate((y_test_df.values, np.reshape(train_labels, (-1, 1))))
|
|
||||||
)
|
|
||||||
classification_metrics = list(constants.CLASSIFICATION_SCALAR_SET)
|
|
||||||
scores = scoring.score_classification(
|
|
||||||
y_test_df.values, predicted, classification_metrics, class_labels, train_labels
|
|
||||||
)
|
|
||||||
|
|
||||||
print("scores:")
|
|
||||||
print(scores)
|
|
||||||
|
|
||||||
for key, value in scores.items():
|
|
||||||
run.log(key, value)
|
|
||||||
@@ -1,5 +1,21 @@
|
|||||||
{
|
{
|
||||||
"cells": [
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
||||||
|
"\n",
|
||||||
|
"Licensed under the MIT License."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-continuous-retraining
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -31,12 +31,15 @@ try:
|
|||||||
model = Model(ws, args.model_name)
|
model = Model(ws, args.model_name)
|
||||||
last_train_time = model.created_time
|
last_train_time = model.created_time
|
||||||
print("Model was last trained on {0}.".format(last_train_time))
|
print("Model was last trained on {0}.".format(last_train_time))
|
||||||
except Exception as e:
|
except Exception:
|
||||||
print("Could not get last model train time.")
|
print("Could not get last model train time.")
|
||||||
last_train_time = datetime.min.replace(tzinfo=pytz.UTC)
|
last_train_time = datetime.min.replace(tzinfo=pytz.UTC)
|
||||||
|
|
||||||
train_ds = Dataset.get_by_name(ws, args.ds_name)
|
train_ds = Dataset.get_by_name(ws, args.ds_name)
|
||||||
dataset_changed_time = train_ds.data_changed_time
|
dataset_changed_time = train_ds.data_changed_time.replace(tzinfo=pytz.UTC)
|
||||||
|
|
||||||
|
print("dataset_changed_time=" + str(dataset_changed_time))
|
||||||
|
print("last_train_time=" + str(last_train_time))
|
||||||
|
|
||||||
if not dataset_changed_time > last_train_time:
|
if not dataset_changed_time > last_train_time:
|
||||||
print("Cancelling run since there is no new data.")
|
print("Cancelling run since there is no new data.")
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ To run these notebook on your own notebook server, use these installation instru
|
|||||||
The instructions below will install everything you need and then start a Jupyter notebook.
|
The instructions below will install everything you need and then start a Jupyter notebook.
|
||||||
If you would like to use a lighter-weight version of the client that does not install all of the machine learning libraries locally, you can leverage the [experimental notebooks.](experimental/README.md)
|
If you would like to use a lighter-weight version of the client that does not install all of the machine learning libraries locally, you can leverage the [experimental notebooks.](experimental/README.md)
|
||||||
|
|
||||||
### 1. Install mini-conda from [here](https://conda.io/miniconda.html), choose 64-bit Python 3.7 or higher.
|
### 1. Install mini-conda from [here](https://conda.io/miniconda.html), choose 64-bit Python 3.8 or higher.
|
||||||
- **Note**: if you already have conda installed, you can keep using it but it should be version 4.4.10 or later (as shown by: conda -V). If you have a previous version installed, you can update it using the command: conda update conda.
|
- **Note**: if you already have conda installed, you can keep using it but it should be version 4.4.10 or later (as shown by: conda -V). If you have a previous version installed, you can update it using the command: conda update conda.
|
||||||
There's no need to install mini-conda specifically.
|
There's no need to install mini-conda specifically.
|
||||||
|
|
||||||
|
|||||||
@@ -97,7 +97,7 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"print(\"This notebook was created using version 1.49.0 of the Azure ML SDK\")\n",
|
"print(\"This notebook was created using version 1.56.0 of the Azure ML SDK\")\n",
|
||||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -148,7 +148,7 @@
|
|||||||
"from azureml.core.compute_target import ComputeTargetException\n",
|
"from azureml.core.compute_target import ComputeTargetException\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Choose a name for your CPU cluster\n",
|
"# Choose a name for your CPU cluster\n",
|
||||||
"cpu_cluster_name = \"cpu-cluster\"\n",
|
"cpu_cluster_name = \"cpu-codegen\"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Verify that cluster does not exist already\n",
|
"# Verify that cluster does not exist already\n",
|
||||||
"try:\n",
|
"try:\n",
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: codegen-for-autofeaturization
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"print(\"This notebook was created using version 1.49.0 of the Azure ML SDK\")\n",
|
"print(\"This notebook was created using version 1.56.0 of the Azure ML SDK\")\n",
|
||||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -454,10 +454,13 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"attachments": {},
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Note:** Not all datasets produce a y_transformer. The dataset used in the current notebook requires a transformer as the y column data is categorical."
|
"**Note:** Not all datasets produce a y_transformer. The dataset used in the current notebook requires a transformer as the y column data is categorical. \n",
|
||||||
|
"\n",
|
||||||
|
"We will go ahead and download the mlflow transformer model and use it to transform test data that can be used for further experimentation below. To run the commented code, make sure the environment requirement is satisfied. You can go ahead and create the environment from the `conda.yaml` file under `/outputs/featurization/pipeline/` and run the given code in it."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -466,7 +469,7 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"from azureml.automl.core.shared.constants import Transformers\n",
|
"''' from azureml.automl.core.shared.constants import Transformers\n",
|
||||||
"\n",
|
"\n",
|
||||||
"transformers = mlflow.sklearn.load_model(uri) # Using method 1\n",
|
"transformers = mlflow.sklearn.load_model(uri) # Using method 1\n",
|
||||||
"data_transformers = transformers.get_transformers()\n",
|
"data_transformers = transformers.get_transformers()\n",
|
||||||
@@ -474,14 +477,15 @@
|
|||||||
"y_transformer = data_transformers[Transformers.Y_TRANSFORMER]\n",
|
"y_transformer = data_transformers[Transformers.Y_TRANSFORMER]\n",
|
||||||
"\n",
|
"\n",
|
||||||
"X_test = x_transformer.transform(X_test_data)\n",
|
"X_test = x_transformer.transform(X_test_data)\n",
|
||||||
"y_test = y_transformer.transform(y_test_data)"
|
"y_test = y_transformer.transform(y_test_data) '''"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"attachments": {},
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Run the following cell to see the featurization summary of X and y transformers. "
|
"Run the following cell to see the featurization summary of X and y transformers. Uncomment to use. "
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -490,10 +494,10 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"X_data_summary = x_transformer.get_featurization_summary(is_user_friendly=False)\n",
|
"''' X_data_summary = x_transformer.get_featurization_summary(is_user_friendly=False)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"summary_df = pd.DataFrame.from_records(X_data_summary)\n",
|
"summary_df = pd.DataFrame.from_records(X_data_summary)\n",
|
||||||
"summary_df"
|
"summary_df '''"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -544,10 +548,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"attachments": {},
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Another way to load the data is to go to the above autofeaturization experiment and check for the featurized dataset ids under `Output datasets`. Uncomment and replace them accordingly below to use."
|
"Another way to load the data is to go to the above autofeaturization experiment and check for the featurized dataset ids under `Output datasets`. Uncomment and replace them accordingly below, to use."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -597,10 +602,20 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"attachments": {},
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Here we are passing our training data to the lightgbm classifier, any custom model can be used with your data."
|
"Here we are passing our training data to the lightgbm classifier, any custom model can be used with your data. Let us first install lightgbm."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"! pip install lightgbm"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -612,11 +627,27 @@
|
|||||||
"import lightgbm as lgb\n",
|
"import lightgbm as lgb\n",
|
||||||
"\n",
|
"\n",
|
||||||
"model = lgb.LGBMClassifier(learning_rate=0.08,max_depth=-5,random_state=42)\n",
|
"model = lgb.LGBMClassifier(learning_rate=0.08,max_depth=-5,random_state=42)\n",
|
||||||
"model.fit(X_train, y_train, sample_weight=sample_weight, eval_set=[(X_test, y_test),(X_train, y_train)],\n",
|
"model.fit(X_train, y_train, sample_weight=sample_weight)"
|
||||||
" verbose=20,eval_metric='logloss')\n",
|
]
|
||||||
"\n",
|
},
|
||||||
|
{
|
||||||
|
"attachments": {},
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Once training is done, the test data obtained after transforming from the above downloaded transformer can be used to calculate the accuracy "
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
"print('Training accuracy {:.4f}'.format(model.score(X_train, y_train)))\n",
|
"print('Training accuracy {:.4f}'.format(model.score(X_train, y_train)))\n",
|
||||||
"print('Testing accuracy {:.4f}'.format(model.score(X_test, y_test)))"
|
"\n",
|
||||||
|
"# Uncomment below to test the model on test data \n",
|
||||||
|
"# print('Testing accuracy {:.4f}'.format(model.score(X_test, y_test)))"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -654,45 +685,8 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"y_pred = model.predict(X_test)"
|
"# Uncomment below to test the model on test data\n",
|
||||||
]
|
"# y_pred = model.predict(X_test)"
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Calculate metrics for the prediction\n",
|
|
||||||
"\n",
|
|
||||||
"Now visualize the data on a scatter plot to show what our truth (actual) values are compared to the predicted values \n",
|
|
||||||
"from the trained model that was returned."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from sklearn.metrics import confusion_matrix\n",
|
|
||||||
"from matplotlib import pyplot as plt\n",
|
|
||||||
"import numpy as np\n",
|
|
||||||
"import itertools\n",
|
|
||||||
"\n",
|
|
||||||
"cf =confusion_matrix(y_test,y_pred)\n",
|
|
||||||
"plt.imshow(cf,cmap=plt.cm.Blues,interpolation='nearest')\n",
|
|
||||||
"plt.colorbar()\n",
|
|
||||||
"plt.title('Confusion Matrix')\n",
|
|
||||||
"plt.xlabel('Predicted')\n",
|
|
||||||
"plt.ylabel('Actual')\n",
|
|
||||||
"class_labels = ['False','True']\n",
|
|
||||||
"tick_marks = np.arange(len(class_labels))\n",
|
|
||||||
"plt.xticks(tick_marks,class_labels)\n",
|
|
||||||
"plt.yticks([-0.5,0,1,1.5],['','False','True',''])\n",
|
|
||||||
"# plotting text value inside cells\n",
|
|
||||||
"thresh = cf.max() / 2.\n",
|
|
||||||
"for i,j in itertools.product(range(cf.shape[0]),range(cf.shape[1])):\n",
|
|
||||||
" plt.text(j,i,format(cf[i,j],'d'),horizontalalignment='center',color='white' if cf[i,j] >thresh else 'black')\n",
|
|
||||||
"plt.show()"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: custom-model-training-from-autofeaturization-run
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"print(\"This notebook was created using version 1.49.0 of the Azure ML SDK\")\n",
|
"print(\"This notebook was created using version 1.56.0 of the Azure ML SDK\")\n",
|
||||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-classification-credit-card-fraud-local-managed
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"print(\"This notebook was created using version 1.49.0 of the Azure ML SDK\")\n",
|
"print(\"This notebook was created using version 1.56.0 of the Azure ML SDK\")\n",
|
||||||
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-regression-model-proxy
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
""
|
""
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-forecasting-backtest-many-models
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Licensed under the MIT License.\n",
|
"Licensed under the MIT License.\n",
|
||||||
""
|
""
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-forecasting-backtest-single-model
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -16,6 +16,13 @@
|
|||||||
""
|
""
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"<font color=\"red\" size=\"5\"><strong>!Important!</strong> </br>This notebook is outdated and is not supported by the AutoML Team. Please use the supported version ([link](https://github.com/Azure/azureml-examples/tree/main/sdk/python/jobs/automl-standalone-jobs/automl-forecasting-task-bike-share)).</font>"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
@@ -61,7 +68,11 @@
|
|||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": null,
|
||||||
"metadata": {},
|
"metadata": {
|
||||||
|
"gather": {
|
||||||
|
"logged": 1680248038565
|
||||||
|
}
|
||||||
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"import json\n",
|
"import json\n",
|
||||||
@@ -170,25 +181,6 @@
|
|||||||
"source": [
|
"source": [
|
||||||
"## Data\n",
|
"## Data\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The [Machine Learning service workspace](https://docs.microsoft.com/en-us/azure/machine-learning/service/concept-workspace) is paired with the storage account, which contains the default data store. We will use it to upload the bike share data and create [tabular dataset](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.data.tabulardataset?view=azure-ml-py) for training. A tabular dataset defines a series of lazily-evaluated, immutable operations to load data from the data source into tabular representation."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"datastore = ws.get_default_datastore()\n",
|
|
||||||
"datastore.upload_files(\n",
|
|
||||||
" files=[\"./bike-no.csv\"], target_path=\"dataset/\", overwrite=True, show_progress=True\n",
|
|
||||||
")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Let's set up what we know about the dataset. \n",
|
"Let's set up what we know about the dataset. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"**Target column** is what we want to forecast.\n",
|
"**Target column** is what we want to forecast.\n",
|
||||||
@@ -206,25 +198,50 @@
|
|||||||
"time_column_name = \"date\""
|
"time_column_name = \"date\""
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"nteract": {
|
||||||
|
"transient": {
|
||||||
|
"deleting": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"You are now ready to load the historical bike share data. We will load the CSV file into a plain pandas DataFrame."
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": null,
|
||||||
"metadata": {},
|
"metadata": {
|
||||||
|
"jupyter": {
|
||||||
|
"outputs_hidden": false,
|
||||||
|
"source_hidden": false
|
||||||
|
},
|
||||||
|
"nteract": {
|
||||||
|
"transient": {
|
||||||
|
"deleting": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"dataset = Dataset.Tabular.from_delimited_files(\n",
|
"all_data = pd.read_csv(\"bike-no.csv\", parse_dates=[time_column_name])\n",
|
||||||
" path=[(datastore, \"dataset/bike-no.csv\")]\n",
|
|
||||||
").with_timestamp_columns(fine_grain_timestamp=time_column_name)\n",
|
|
||||||
"\n",
|
"\n",
|
||||||
"# Drop the columns 'casual' and 'registered' as these columns are a breakdown of the total and therefore a leak.\n",
|
"# Drop the columns 'casual' and 'registered' as these columns are a breakdown of the total and therefore a leak.\n",
|
||||||
"dataset = dataset.drop_columns(columns=[\"casual\", \"registered\"])\n",
|
"all_data.drop([\"casual\", \"registered\"], axis=1, inplace=True)"
|
||||||
"\n",
|
|
||||||
"dataset.take(5).to_pandas_dataframe().reset_index(drop=True)"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {
|
||||||
|
"nteract": {
|
||||||
|
"transient": {
|
||||||
|
"deleting": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"source": [
|
"source": [
|
||||||
"### Split the data\n",
|
"### Split the data\n",
|
||||||
"\n",
|
"\n",
|
||||||
@@ -234,22 +251,63 @@
|
|||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": null,
|
||||||
"metadata": {},
|
"metadata": {
|
||||||
|
"gather": {
|
||||||
|
"logged": 1680247376789
|
||||||
|
},
|
||||||
|
"jupyter": {
|
||||||
|
"outputs_hidden": false,
|
||||||
|
"source_hidden": false
|
||||||
|
},
|
||||||
|
"nteract": {
|
||||||
|
"transient": {
|
||||||
|
"deleting": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"# select data that occurs before a specified date\n",
|
"# select data that occurs before a specified date\n",
|
||||||
"train = dataset.time_before(datetime(2012, 8, 31), include_boundary=True)\n",
|
"train = all_data[all_data[time_column_name] <= pd.Timestamp(\"2012-08-31\")].copy()\n",
|
||||||
"train.to_pandas_dataframe().tail(5).reset_index(drop=True)"
|
"test = all_data[all_data[time_column_name] >= pd.Timestamp(\"2012-09-01\")].copy()"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Upload data to datastore\n",
|
||||||
|
"\n",
|
||||||
|
"The [Machine Learning service workspace](https://docs.microsoft.com/en-us/azure/machine-learning/service/concept-workspace) is paired with the storage account, which contains the default data store. We will use it to upload the bike share data and create [tabular dataset](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.data.tabulardataset?view=azure-ml-py) for training. A tabular dataset defines a series of lazily-evaluated, immutable operations to load data from the data source into tabular representation."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": null,
|
||||||
"metadata": {},
|
"metadata": {
|
||||||
|
"jupyter": {
|
||||||
|
"outputs_hidden": false,
|
||||||
|
"source_hidden": false
|
||||||
|
},
|
||||||
|
"nteract": {
|
||||||
|
"transient": {
|
||||||
|
"deleting": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"test = dataset.time_after(datetime(2012, 9, 1), include_boundary=True)\n",
|
"from azureml.data.dataset_factory import TabularDatasetFactory\n",
|
||||||
"test.to_pandas_dataframe().head(5).reset_index(drop=True)"
|
"\n",
|
||||||
|
"datastore = ws.get_default_datastore()\n",
|
||||||
|
"\n",
|
||||||
|
"train_dataset = TabularDatasetFactory.register_pandas_dataframe(\n",
|
||||||
|
" train, target=(datastore, \"dataset/\"), name=\"bike_no_train\"\n",
|
||||||
|
")\n",
|
||||||
|
"\n",
|
||||||
|
"test_dataset = TabularDatasetFactory.register_pandas_dataframe(\n",
|
||||||
|
" test, target=(datastore, \"dataset/\"), name=\"bike_no_test\"\n",
|
||||||
|
")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -360,7 +418,7 @@
|
|||||||
" featurization=featurization_config,\n",
|
" featurization=featurization_config,\n",
|
||||||
" blocked_models=[\"ExtremeRandomTrees\"],\n",
|
" blocked_models=[\"ExtremeRandomTrees\"],\n",
|
||||||
" experiment_timeout_hours=0.3,\n",
|
" experiment_timeout_hours=0.3,\n",
|
||||||
" training_data=train,\n",
|
" training_data=train_dataset,\n",
|
||||||
" label_column_name=target_column_name,\n",
|
" label_column_name=target_column_name,\n",
|
||||||
" compute_target=compute_target,\n",
|
" compute_target=compute_target,\n",
|
||||||
" enable_early_stopping=True,\n",
|
" enable_early_stopping=True,\n",
|
||||||
@@ -546,7 +604,7 @@
|
|||||||
"from run_forecast import run_rolling_forecast\n",
|
"from run_forecast import run_rolling_forecast\n",
|
||||||
"\n",
|
"\n",
|
||||||
"remote_run = run_rolling_forecast(\n",
|
"remote_run = run_rolling_forecast(\n",
|
||||||
" test_experiment, compute_target, best_run, test, target_column_name\n",
|
" test_experiment, compute_target, best_run, test_dataset, target_column_name\n",
|
||||||
")\n",
|
")\n",
|
||||||
"remote_run"
|
"remote_run"
|
||||||
]
|
]
|
||||||
@@ -722,6 +780,9 @@
|
|||||||
],
|
],
|
||||||
"friendly_name": "Forecasting BikeShare Demand",
|
"friendly_name": "Forecasting BikeShare Demand",
|
||||||
"index_order": 1,
|
"index_order": 1,
|
||||||
|
"kernel_info": {
|
||||||
|
"name": "python38-azureml"
|
||||||
|
},
|
||||||
"kernelspec": {
|
"kernelspec": {
|
||||||
"display_name": "Python 3.8 - AzureML",
|
"display_name": "Python 3.8 - AzureML",
|
||||||
"language": "python",
|
"language": "python",
|
||||||
@@ -737,11 +798,19 @@
|
|||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.7.13"
|
"version": "3.8.10"
|
||||||
|
},
|
||||||
|
"microsoft": {
|
||||||
|
"ms_spell_check": {
|
||||||
|
"ms_spell_check_language": "en"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"mimetype": "text/x-python",
|
"mimetype": "text/x-python",
|
||||||
"name": "python",
|
"name": "python",
|
||||||
"npconvert_exporter": "python",
|
"npconvert_exporter": "python",
|
||||||
|
"nteract": {
|
||||||
|
"version": "nteract-front-end@1.0.0"
|
||||||
|
},
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"tags": [
|
"tags": [
|
||||||
"Forecasting"
|
"Forecasting"
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-forecasting-bike-share
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import argparse
|
import argparse
|
||||||
from azureml.core import Dataset, Run
|
from azureml.core import Dataset, Run
|
||||||
from sklearn.externals import joblib
|
import joblib
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
|||||||
@@ -16,6 +16,13 @@
|
|||||||
""
|
""
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"<font color=\"red\" size=\"5\"><strong>!Important!</strong> </br>This notebook is outdated and is not supported by the AutoML Team. Please use the supported version ([link](https://github.com/Azure/azureml-examples/blob/main/sdk/python/jobs/automl-standalone-jobs/automl-forecasting-task-energy-demand/automl-forecasting-task-energy-demand-advanced-mlflow.ipynb)).</font>"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
@@ -260,8 +267,12 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"# split into train based on time\n",
|
"# split into train based on time\n",
|
||||||
"train = dataset.time_before(datetime(2017, 8, 8, 5), include_boundary=True)\n",
|
"train = (\n",
|
||||||
"train.to_pandas_dataframe().reset_index(drop=True).sort_values(time_column_name).tail(5)"
|
" dataset.time_before(datetime(2017, 8, 8, 5), include_boundary=True)\n",
|
||||||
|
" .to_pandas_dataframe()\n",
|
||||||
|
" .reset_index(drop=True)\n",
|
||||||
|
")\n",
|
||||||
|
"train.sort_values(time_column_name).tail(5)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -271,8 +282,39 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"# split into test based on time\n",
|
"# split into test based on time\n",
|
||||||
"test = dataset.time_between(datetime(2017, 8, 8, 6), datetime(2017, 8, 10, 5))\n",
|
"test = (\n",
|
||||||
"test.to_pandas_dataframe().reset_index(drop=True).head(5)"
|
" dataset.time_between(datetime(2017, 8, 8, 6), datetime(2017, 8, 10, 5))\n",
|
||||||
|
" .to_pandas_dataframe()\n",
|
||||||
|
" .reset_index(drop=True)\n",
|
||||||
|
")\n",
|
||||||
|
"test.head(5)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {
|
||||||
|
"jupyter": {
|
||||||
|
"outputs_hidden": false
|
||||||
|
},
|
||||||
|
"nteract": {
|
||||||
|
"transient": {
|
||||||
|
"deleting": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"# register the splitted train and test data in workspace storage\n",
|
||||||
|
"from azureml.data.dataset_factory import TabularDatasetFactory\n",
|
||||||
|
"\n",
|
||||||
|
"datastore = ws.get_default_datastore()\n",
|
||||||
|
"train_dataset = TabularDatasetFactory.register_pandas_dataframe(\n",
|
||||||
|
" train, target=(datastore, \"dataset/\"), name=\"nyc_energy_train\"\n",
|
||||||
|
")\n",
|
||||||
|
"test_dataset = TabularDatasetFactory.register_pandas_dataframe(\n",
|
||||||
|
" test, target=(datastore, \"dataset/\"), name=\"nyc_energy_test\"\n",
|
||||||
|
")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -361,7 +403,7 @@
|
|||||||
" primary_metric=\"normalized_root_mean_squared_error\",\n",
|
" primary_metric=\"normalized_root_mean_squared_error\",\n",
|
||||||
" blocked_models=[\"ExtremeRandomTrees\", \"AutoArima\", \"Prophet\"],\n",
|
" blocked_models=[\"ExtremeRandomTrees\", \"AutoArima\", \"Prophet\"],\n",
|
||||||
" experiment_timeout_hours=0.3,\n",
|
" experiment_timeout_hours=0.3,\n",
|
||||||
" training_data=train,\n",
|
" training_data=train_dataset,\n",
|
||||||
" label_column_name=target_column_name,\n",
|
" label_column_name=target_column_name,\n",
|
||||||
" compute_target=compute_target,\n",
|
" compute_target=compute_target,\n",
|
||||||
" enable_early_stopping=True,\n",
|
" enable_early_stopping=True,\n",
|
||||||
@@ -521,7 +563,7 @@
|
|||||||
" test_experiment=test_experiment,\n",
|
" test_experiment=test_experiment,\n",
|
||||||
" compute_target=compute_target,\n",
|
" compute_target=compute_target,\n",
|
||||||
" train_run=best_run,\n",
|
" train_run=best_run,\n",
|
||||||
" test_dataset=test,\n",
|
" test_dataset=test_dataset,\n",
|
||||||
" target_column_name=target_column_name,\n",
|
" target_column_name=target_column_name,\n",
|
||||||
")\n",
|
")\n",
|
||||||
"remote_run_infer.wait_for_completion(show_output=False)\n",
|
"remote_run_infer.wait_for_completion(show_output=False)\n",
|
||||||
@@ -627,7 +669,7 @@
|
|||||||
" \"Prophet\",\n",
|
" \"Prophet\",\n",
|
||||||
" ], # These models are blocked for tutorial purposes, remove this for real use cases.\n",
|
" ], # These models are blocked for tutorial purposes, remove this for real use cases.\n",
|
||||||
" experiment_timeout_hours=0.3,\n",
|
" experiment_timeout_hours=0.3,\n",
|
||||||
" training_data=train,\n",
|
" training_data=train_dataset,\n",
|
||||||
" label_column_name=target_column_name,\n",
|
" label_column_name=target_column_name,\n",
|
||||||
" compute_target=compute_target,\n",
|
" compute_target=compute_target,\n",
|
||||||
" enable_early_stopping=True,\n",
|
" enable_early_stopping=True,\n",
|
||||||
@@ -698,7 +740,7 @@
|
|||||||
" test_experiment=test_experiment_advanced,\n",
|
" test_experiment=test_experiment_advanced,\n",
|
||||||
" compute_target=compute_target,\n",
|
" compute_target=compute_target,\n",
|
||||||
" train_run=best_run_lags,\n",
|
" train_run=best_run_lags,\n",
|
||||||
" test_dataset=test,\n",
|
" test_dataset=test_dataset,\n",
|
||||||
" target_column_name=target_column_name,\n",
|
" target_column_name=target_column_name,\n",
|
||||||
" inference_folder=\"./forecast_advanced\",\n",
|
" inference_folder=\"./forecast_advanced\",\n",
|
||||||
")\n",
|
")\n",
|
||||||
@@ -766,6 +808,9 @@
|
|||||||
"how-to-use-azureml",
|
"how-to-use-azureml",
|
||||||
"automated-machine-learning"
|
"automated-machine-learning"
|
||||||
],
|
],
|
||||||
|
"kernel_info": {
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
"kernelspec": {
|
"kernelspec": {
|
||||||
"display_name": "Python 3.8 - AzureML",
|
"display_name": "Python 3.8 - AzureML",
|
||||||
"language": "python",
|
"language": "python",
|
||||||
@@ -781,7 +826,15 @@
|
|||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.8.5"
|
"version": "3.8.10"
|
||||||
|
},
|
||||||
|
"microsoft": {
|
||||||
|
"ms_spell_check": {
|
||||||
|
"ms_spell_check_language": "en"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nteract": {
|
||||||
|
"version": "nteract-front-end@1.0.0"
|
||||||
},
|
},
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"interpreter": {
|
"interpreter": {
|
||||||
@@ -790,5 +843,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nbformat": 4,
|
"nbformat": 4,
|
||||||
"nbformat_minor": 2
|
"nbformat_minor": 4
|
||||||
}
|
}
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-forecasting-energy-demand
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -6,7 +6,7 @@ compute instance.
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
from azureml.core import Dataset, Run
|
from azureml.core import Dataset, Run
|
||||||
from sklearn.externals import joblib
|
import joblib
|
||||||
from pandas.tseries.frequencies import to_offset
|
from pandas.tseries.frequencies import to_offset
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-forecasting-function
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -19,7 +19,14 @@
|
|||||||
"hidePrompt": false
|
"hidePrompt": false
|
||||||
},
|
},
|
||||||
"source": [
|
"source": [
|
||||||
""
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"<font color=\"red\" size=\"5\"><strong>!Important!</strong> </br>This notebook is outdated and is not supported by the AutoML Team. Please use the supported version ([link](https://github.com/Azure/azureml-examples/tree/main/sdk/python/jobs/automl-standalone-jobs/automl-forecasting-github-dau)).</font>"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -382,7 +389,7 @@
|
|||||||
"automl_config = AutoMLConfig(\n",
|
"automl_config = AutoMLConfig(\n",
|
||||||
" task=\"forecasting\",\n",
|
" task=\"forecasting\",\n",
|
||||||
" primary_metric=\"normalized_root_mean_squared_error\",\n",
|
" primary_metric=\"normalized_root_mean_squared_error\",\n",
|
||||||
" experiment_timeout_hours=1,\n",
|
" experiment_timeout_hours=1.5,\n",
|
||||||
" training_data=train_dataset,\n",
|
" training_data=train_dataset,\n",
|
||||||
" label_column_name=target_column_name,\n",
|
" label_column_name=target_column_name,\n",
|
||||||
" validation_data=valid_dataset,\n",
|
" validation_data=valid_dataset,\n",
|
||||||
@@ -695,7 +702,7 @@
|
|||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.6.9"
|
"version": "3.8.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nbformat": 4,
|
"nbformat": 4,
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-forecasting-github-dau
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -4,7 +4,7 @@ import os
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
from sklearn.externals import joblib
|
import joblib
|
||||||
from sklearn.metrics import mean_absolute_error, mean_squared_error
|
from sklearn.metrics import mean_absolute_error, mean_squared_error
|
||||||
|
|
||||||
from azureml.automl.runtime.shared.score import scoring, constants
|
from azureml.automl.runtime.shared.score import scoring, constants
|
||||||
|
|||||||
@@ -16,6 +16,13 @@
|
|||||||
""
|
""
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"<font color=\"red\" size=\"5\"><strong>!Important!</strong> </br>This notebook is outdated and is not supported by the AutoML Team. Please use the supported version ([link](https://github.com/Azure/azureml-examples/tree/main/sdk/python/jobs/pipelines/1k_demand_forecasting_with_pipeline_components/automl-forecasting-demand-hierarchical-timeseries-in-pipeline)).</font>"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
@@ -666,7 +673,7 @@
|
|||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.6.8"
|
"version": "3.8.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nbformat": 4,
|
"nbformat": 4,
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-forecasting-hierarchical-timeseries
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -16,6 +16,13 @@
|
|||||||
""
|
""
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"<font color=\"red\" size=\"5\"><strong>!Important!</strong> </br>This notebook is outdated and is not supported by the AutoML Team. Please use the supported version ([link](https://github.com/Azure/azureml-examples/tree/main/sdk/python/jobs/pipelines/1k_demand_forecasting_with_pipeline_components/automl-forecasting-demand-many-models-in-pipeline)).</font>"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
@@ -306,7 +313,7 @@
|
|||||||
"from azureml.core.compute import ComputeTarget, AmlCompute\n",
|
"from azureml.core.compute import ComputeTarget, AmlCompute\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Name your cluster\n",
|
"# Name your cluster\n",
|
||||||
"compute_name = \"mm-compute\"\n",
|
"compute_name = \"mm-compute-v1\"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"if compute_name in ws.compute_targets:\n",
|
"if compute_name in ws.compute_targets:\n",
|
||||||
@@ -316,7 +323,7 @@
|
|||||||
"else:\n",
|
"else:\n",
|
||||||
" print(\"Creating a new compute target...\")\n",
|
" print(\"Creating a new compute target...\")\n",
|
||||||
" provisioning_config = AmlCompute.provisioning_configuration(\n",
|
" provisioning_config = AmlCompute.provisioning_configuration(\n",
|
||||||
" vm_size=\"STANDARD_D16S_V3\", max_nodes=20\n",
|
" vm_size=\"STANDARD_D14_V2\", max_nodes=20\n",
|
||||||
" )\n",
|
" )\n",
|
||||||
" # Create the compute target\n",
|
" # Create the compute target\n",
|
||||||
" compute_target = ComputeTarget.create(ws, compute_name, provisioning_config)\n",
|
" compute_target = ComputeTarget.create(ws, compute_name, provisioning_config)\n",
|
||||||
@@ -878,7 +885,7 @@
|
|||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.8.5"
|
"version": "3.8.10"
|
||||||
},
|
},
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"interpreter": {
|
"interpreter": {
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-forecasting-many-models
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -16,6 +16,13 @@
|
|||||||
""
|
""
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"<font color=\"red\" size=\"5\"><strong>!Important!</strong> </br>This notebook is outdated and is not supported by the AutoML Team. Please use the supported version ([link](https://github.com/Azure/azureml-examples/tree/main/sdk/python/jobs/automl-standalone-jobs/automl-forecasting-orange-juice-sales)).</font>"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
@@ -242,7 +249,9 @@
|
|||||||
" time_series_id_column_names, group_keys=False\n",
|
" time_series_id_column_names, group_keys=False\n",
|
||||||
" )\n",
|
" )\n",
|
||||||
" df_head = df_grouped.apply(lambda dfg: dfg.iloc[:-n])\n",
|
" df_head = df_grouped.apply(lambda dfg: dfg.iloc[:-n])\n",
|
||||||
|
" df_head.reset_index(inplace=True, drop=True)\n",
|
||||||
" df_tail = df_grouped.apply(lambda dfg: dfg.iloc[-n:])\n",
|
" df_tail = df_grouped.apply(lambda dfg: dfg.iloc[-n:])\n",
|
||||||
|
" df_tail.reset_index(inplace=True, drop=True)\n",
|
||||||
" return df_head, df_tail\n",
|
" return df_head, df_tail\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
@@ -715,7 +724,7 @@
|
|||||||
" description=\"Automl forecasting sample service\",\n",
|
" description=\"Automl forecasting sample service\",\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"aci_service_name = \"automl-oj-forecast-01\"\n",
|
"aci_service_name = \"automl-oj-forecast-03\"\n",
|
||||||
"print(aci_service_name)\n",
|
"print(aci_service_name)\n",
|
||||||
"aci_service = Model.deploy(ws, aci_service_name, [model], inference_config, aciconfig)\n",
|
"aci_service = Model.deploy(ws, aci_service_name, [model], inference_config, aciconfig)\n",
|
||||||
"aci_service.wait_for_deployment(True)\n",
|
"aci_service.wait_for_deployment(True)\n",
|
||||||
@@ -792,7 +801,7 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"serv = Webservice(ws, \"automl-oj-forecast-01\")\n",
|
"serv = Webservice(ws, \"automl-oj-forecast-03\")\n",
|
||||||
"serv.delete() # don't do it accidentally"
|
"serv.delete() # don't do it accidentally"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -835,7 +844,7 @@
|
|||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.8.5"
|
"version": "3.8.10"
|
||||||
},
|
},
|
||||||
"tags": [
|
"tags": [
|
||||||
"None"
|
"None"
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-forecasting-orange-juice-sales
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -6,7 +6,7 @@ compute instance.
|
|||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
from azureml.core import Dataset, Run
|
from azureml.core import Dataset, Run
|
||||||
from sklearn.externals import joblib
|
import joblib
|
||||||
from pandas.tseries.frequencies import to_offset
|
from pandas.tseries.frequencies import to_offset
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
|||||||
@@ -1,5 +1,37 @@
|
|||||||
{
|
{
|
||||||
"cells": [
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
||||||
|
"\n",
|
||||||
|
"Licensed under the MIT License."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"<font color=\"red\" size=\"5\"><strong>!Important!</strong> </br>This notebook is outdated and is not supported by the AutoML Team. Please use the supported version ([link](https://github.com/Azure/azureml-examples/tree/main/sdk/python/jobs/pipelines/1h_automl_in_pipeline/automl-forecasting-in-pipeline)).</font>\n",
|
||||||
|
"</br>\n",
|
||||||
|
"</br>\n",
|
||||||
|
"<font color=\"red\" size=\"5\">\n",
|
||||||
|
"For examples illustrating how to build pipelines with components, please use the following links:</font>\n",
|
||||||
|
"<ul>\n",
|
||||||
|
" <li><a href=\"https://github.com/Azure/azureml-examples/tree/main/sdk/python/jobs/pipelines/1k_demand_forecasting_with_pipeline_components/automl-forecasting-demand-many-models-in-pipeline\">Many Models</a></li>\n",
|
||||||
|
" <li><a href=\"https://github.com/Azure/azureml-examples/tree/main/sdk/python/jobs/pipelines/1k_demand_forecasting_with_pipeline_components/automl-forecasting-demand-hierarchical-timeseries-in-pipeline\">Hierarchical Time Series</a></li>\n",
|
||||||
|
" <li><a href=\"https://github.com/Azure/azureml-examples/tree/main/sdk/python/jobs/automl-standalone-jobs/automl-forecasting-distributed-tcn\">Distributed TCN</a></li>\n",
|
||||||
|
"</ul>"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
@@ -39,7 +71,6 @@
|
|||||||
"import logging\n",
|
"import logging\n",
|
||||||
"import os\n",
|
"import os\n",
|
||||||
"\n",
|
"\n",
|
||||||
"from matplotlib import pyplot as plt\n",
|
|
||||||
"import pandas as pd\n",
|
"import pandas as pd\n",
|
||||||
"\n",
|
"\n",
|
||||||
"import azureml.core\n",
|
"import azureml.core\n",
|
||||||
@@ -425,8 +456,6 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"from azureml.pipeline.core import PipelineData\n",
|
|
||||||
"\n",
|
|
||||||
"# The model name with which to register the trained model in the workspace.\n",
|
"# The model name with which to register the trained model in the workspace.\n",
|
||||||
"model_name_str = \"ojmodel\"\n",
|
"model_name_str = \"ojmodel\"\n",
|
||||||
"model_name = PipelineParameter(\"model_name\", default_value=model_name_str)\n",
|
"model_name = PipelineParameter(\"model_name\", default_value=model_name_str)\n",
|
||||||
@@ -555,40 +584,15 @@
|
|||||||
"metadata": {},
|
"metadata": {},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"from azureml.core import Model\n",
|
"from azureml.train.automl.run import AutoMLRun\n",
|
||||||
"\n",
|
"\n",
|
||||||
"model = Model(ws, model_name_str)\n",
|
"for step in training_pipeline_run.get_steps():\n",
|
||||||
"download_path = model.download(model_name_str, exist_ok=True)"
|
" if step.properties.get(\"StepType\") == \"AutoMLStep\":\n",
|
||||||
]
|
" automl_run = AutoMLRun(experiment, step.id)\n",
|
||||||
},
|
" break\n",
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"After all the files are downloaded, we can generate the run config for inference runs."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Environment, RunConfiguration\n",
|
|
||||||
"from azureml.core.conda_dependencies import CondaDependencies\n",
|
|
||||||
"\n",
|
"\n",
|
||||||
"env_file = os.path.join(download_path, \"conda_env_v_1_0_0.yml\")\n",
|
"best_run = automl_run.get_best_child()\n",
|
||||||
"inference_env = Environment(\"oj-inference-env\")\n",
|
"inference_env = best_run.get_environment()"
|
||||||
"inference_env.python.conda_dependencies = CondaDependencies(\n",
|
|
||||||
" conda_dependencies_file_path=env_file\n",
|
|
||||||
")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"[Optional] The enviroment can also be assessed from the training run using `get_environment()` API."
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-forecasting-pipelines
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -6,7 +6,7 @@ import numpy as np
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
from pandas.tseries.frequencies import to_offset
|
from pandas.tseries.frequencies import to_offset
|
||||||
from sklearn.externals import joblib
|
import joblib
|
||||||
from sklearn.metrics import mean_absolute_error, mean_squared_error
|
from sklearn.metrics import mean_absolute_error, mean_squared_error
|
||||||
|
|
||||||
from azureml.data.dataset_factory import TabularDatasetFactory
|
from azureml.data.dataset_factory import TabularDatasetFactory
|
||||||
@@ -30,7 +30,7 @@ def infer_forecasting_dataset_tcn(
|
|||||||
|
|
||||||
run = Run.get_context()
|
run = Run.get_context()
|
||||||
|
|
||||||
registered_train = TabularDatasetFactory.register_pandas_dataframe(
|
TabularDatasetFactory.register_pandas_dataframe(
|
||||||
df_all,
|
df_all,
|
||||||
target=(
|
target=(
|
||||||
run.experiment.workspace.get_default_datastore(),
|
run.experiment.workspace.get_default_datastore(),
|
||||||
|
|||||||
@@ -20,7 +20,14 @@
|
|||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"In this notebook we will explore the univaraite time-series data to determine the settings for an automated ML experiment. We will follow the thought process depicted in the following diagram:<br/>\n",
|
"<font color=\"red\" size=\"5\"><strong>!Important!</strong> </br>This notebook is outdated and is not supported by the AutoML Team. Please use the supported version ([link](https://github.com/Azure/azureml-examples/tree/main/sdk/python/jobs/automl-standalone-jobs/automl-forecasting-recipes-univariate)).</font>"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"In this notebook we will explore the univariate time-series data to determine the settings for an automated ML experiment. We will follow the thought process depicted in the following diagram:<br/>\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The objective is to answer the following questions:\n",
|
"The objective is to answer the following questions:\n",
|
||||||
@@ -32,11 +39,11 @@
|
|||||||
" </ul>\n",
|
" </ul>\n",
|
||||||
" <li>Is the data stationary? </li>\n",
|
" <li>Is the data stationary? </li>\n",
|
||||||
" <ul style=\"margin-top:-1px; list-style-type:none\"> \n",
|
" <ul style=\"margin-top:-1px; list-style-type:none\"> \n",
|
||||||
" <li> Importance: In the absense of features that capture trend behavior, ML models (regression and tree based) are not well equiped to predict stochastic trends. Working with stationary data solves this problem. </li>\n",
|
" <li> Importance: In the absence of features that capture trend behavior, ML models (regression and tree based) are not well equipped to predict stochastic trends. Working with stationary data solves this problem. </li>\n",
|
||||||
" </ul>\n",
|
" </ul>\n",
|
||||||
" <li>Is there a detectable auto-regressive pattern in the stationary data? </li>\n",
|
" <li>Is there a detectable auto-regressive pattern in the stationary data? </li>\n",
|
||||||
" <ul style=\"margin-top:-1px; list-style-type:none\"> \n",
|
" <ul style=\"margin-top:-1px; list-style-type:none\"> \n",
|
||||||
" <li> Importance: The accuracy of ML models can be improved if serial correlation is modeled by including lags of the dependent/target varaible as features. Including target lags in every experiment by default will result in a regression in accuracy scores if such setting is not warranted. </li>\n",
|
" <li> Importance: The accuracy of ML models can be improved if serial correlation is modeled by including lags of the dependent/target variable as features. Including target lags in every experiment by default will result in a regression in accuracy scores if such setting is not warranted. </li>\n",
|
||||||
" </ul>\n",
|
" </ul>\n",
|
||||||
"</ol>\n",
|
"</ol>\n",
|
||||||
"\n",
|
"\n",
|
||||||
@@ -109,7 +116,7 @@
|
|||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The graph plots the alcohol sales in the United States. Because the data is trending, it can be difficult to see cycles, seasonality or other interestng behaviors due to the scaling issues. For example, if there is a seasonal pattern, which we will discuss later, we cannot see them on the trending data. In such case, it is worth plotting the same data in first differences."
|
"The graph plots the alcohol sales in the United States. Because the data is trending, it can be difficult to see cycles, seasonality or other interesting behaviors due to the scaling issues. For example, if there is a seasonal pattern, which we will discuss later, we cannot see them on the trending data. In such case, it is worth plotting the same data in first differences."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -335,8 +342,8 @@
|
|||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# 3 Check if there is a clear autoregressive pattern\n",
|
"# 3 Check if there is a clear auto-regressive pattern\n",
|
||||||
"We need to determine if we should include lags of the target variable as features in order to improve forecast accuracy. To do this, we will examine the ACF and partial ACF (PACF) plots of the stationary series. In our case, it is a series in first diffrences.\n",
|
"We need to determine if we should include lags of the target variable as features in order to improve forecast accuracy. To do this, we will examine the ACF and partial ACF (PACF) plots of the stationary series. In our case, it is a series in first differences.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"<ul>\n",
|
"<ul>\n",
|
||||||
" <li> Question: What is an Auto-regressive pattern? What are we looking for? </li>\n",
|
" <li> Question: What is an Auto-regressive pattern? What are we looking for? </li>\n",
|
||||||
@@ -418,11 +425,11 @@
|
|||||||
" </li>\n",
|
" </li>\n",
|
||||||
" where $\\sigma_{xzy}$ is the covariance between two random variables $X$ and $Z$; $\\sigma_x$ and $\\sigma_z$ is the variance for $X$ and $Z$, respectively. The correlation coefficient measures the strength of linear relationship between two random variables. This metric can take any value from -1 to 1. <li/>\n",
|
" where $\\sigma_{xzy}$ is the covariance between two random variables $X$ and $Z$; $\\sigma_x$ and $\\sigma_z$ is the variance for $X$ and $Z$, respectively. The correlation coefficient measures the strength of linear relationship between two random variables. This metric can take any value from -1 to 1. <li/>\n",
|
||||||
" <br/>\n",
|
" <br/>\n",
|
||||||
" <li> The auto-correlation coefficient $\\rho_{Y_{t} Y_{t-k}}$ is the time series equivalent of the correlation coefficient, except instead of measuring linear association between two random variables $X$ and $Z$, it measures the strength of a linear relationship between a random variable $Y_t$ and its lag $Y_{t-k}$ for any positive interger value of $k$. </li> \n",
|
" <li> The auto-correlation coefficient $\\rho_{Y_{t} Y_{t-k}}$ is the time series equivalent of the correlation coefficient, except instead of measuring linear association between two random variables $X$ and $Z$, it measures the strength of a linear relationship between a random variable $Y_t$ and its lag $Y_{t-k}$ for any positive integer value of $k$. </li> \n",
|
||||||
" <br />\n",
|
" <br />\n",
|
||||||
" <li> To visualize the ACF for a particular lag, say lag 2, plot the second lag of a series $y_{t-2}$ on the x-axis, and plot the series itself $y_t$ on the y-axis. The autocorrelation coefficient is the slope of the best fitted regression line and can be interpreted as follows. A one unit increase in the lag of a variable one period ago leads to a $\\rho_{Y_{t} Y_{t-2}}$ units change in the variable in the current period. This interpreation can be applied to any lag. </li> \n",
|
" <li> To visualize the ACF for a particular lag, say lag 2, plot the second lag of a series $y_{t-2}$ on the x-axis, and plot the series itself $y_t$ on the y-axis. The autocorrelation coefficient is the slope of the best fitted regression line and can be interpreted as follows. A one unit increase in the lag of a variable one period ago leads to a $\\rho_{Y_{t} Y_{t-2}}$ units change in the variable in the current period. This interpretation can be applied to any lag. </li> \n",
|
||||||
" <br />\n",
|
" <br />\n",
|
||||||
" <li> In the interpretation posted above we need to be careful not to confuse the word \"leads\" with \"causes\" since these are not the same thing. We do not know the lagged value of the varaible causes it to change. Afterall, there are probably many other features that may explain the movement in $Y_t$. All we are trying to do in this section is to identify situations when the variable contains the strong auto-regressive components that needs to be included in the model to improve forecast accuracy. </li>\n",
|
" <li> In the interpretation posted above we need to be careful not to confuse the word \"leads\" with \"causes\" since these are not the same thing. We do not know the lagged value of the variable causes it to change. After all, there are probably many other features that may explain the movement in $Y_t$. All we are trying to do in this section is to identify situations when the variable contains the strong auto-regressive components that needs to be included in the model to improve forecast accuracy. </li>\n",
|
||||||
" </ul>\n",
|
" </ul>\n",
|
||||||
"</ul>"
|
"</ul>"
|
||||||
]
|
]
|
||||||
@@ -434,7 +441,7 @@
|
|||||||
"<ul>\n",
|
"<ul>\n",
|
||||||
" <li> Question: What is the PACF? </li>\n",
|
" <li> Question: What is the PACF? </li>\n",
|
||||||
" <ul style=\"list-style-type:none;\">\n",
|
" <ul style=\"list-style-type:none;\">\n",
|
||||||
" <li> When describing the ACF we essentially running a regression between a partigular lag of a series, say, lag 4, and the series itself. What this implies is the regression coefficient for lag 4 captures the impact of everything that happens in lags 1, 2 and 3. In other words, if lag 1 is the most important lag and we exclude it from the regression, naturally, the regression model will assign the importance of the 1st lag to the 4th one. Partial auto-correlation function fixes this problem since it measures the contribution of each lag accounting for the information added by the intermediary lags. If we were to illustrate ACF and PACF for the fourth lag using the regression analogy, the difference is a follows: \n",
|
" <li> When describing the ACF we essentially running a regression between a particular lag of a series, say, lag 4, and the series itself. What this implies is the regression coefficient for lag 4 captures the impact of everything that happens in lags 1, 2 and 3. In other words, if lag 1 is the most important lag and we exclude it from the regression, naturally, the regression model will assign the importance of the 1st lag to the 4th one. Partial auto-correlation function fixes this problem since it measures the contribution of each lag accounting for the information added by the intermediary lags. If we were to illustrate ACF and PACF for the fourth lag using the regression analogy, the difference is a follows: \n",
|
||||||
" \\begin{align}\n",
|
" \\begin{align}\n",
|
||||||
" Y_{t} &= a_{0} + a_{4} Y_{t-4} + e_{t} \\\\\n",
|
" Y_{t} &= a_{0} + a_{4} Y_{t-4} + e_{t} \\\\\n",
|
||||||
" Y_{t} &= b_{0} + b_{1} Y_{t-1} + b_{2} Y_{t-2} + b_{3} Y_{t-3} + b_{4} Y_{t-4} + \\varepsilon_{t} \\\\\n",
|
" Y_{t} &= b_{0} + b_{1} Y_{t-1} + b_{2} Y_{t-2} + b_{3} Y_{t-3} + b_{4} Y_{t-4} + \\varepsilon_{t} \\\\\n",
|
||||||
@@ -442,7 +449,7 @@
|
|||||||
" </li>\n",
|
" </li>\n",
|
||||||
" <br/>\n",
|
" <br/>\n",
|
||||||
" <li>\n",
|
" <li>\n",
|
||||||
" Here, you can think of $a_4$ and $b_{4}$ as the auto- and partial auto-correlation coefficients for lag 4. Notice, in the second equation we explicitely accounting for the intermediate lags by adding them as regrerssors.\n",
|
" Here, you can think of $a_4$ and $b_{4}$ as the auto- and partial auto-correlation coefficients for lag 4. Notice, in the second equation we explicitly accounting for the intermediate lags by adding them as regressors.\n",
|
||||||
" </li>\n",
|
" </li>\n",
|
||||||
" </ul>\n",
|
" </ul>\n",
|
||||||
"</ul>"
|
"</ul>"
|
||||||
@@ -455,11 +462,11 @@
|
|||||||
"<ul>\n",
|
"<ul>\n",
|
||||||
" <li> Question: Auto-regressive pattern? What are we looking for? </li>\n",
|
" <li> Question: Auto-regressive pattern? What are we looking for? </li>\n",
|
||||||
" <ul style=\"list-style-type:none;\">\n",
|
" <ul style=\"list-style-type:none;\">\n",
|
||||||
" <li> We are looking for a classical profiles for an AR(p) process such as an exponential decay of an ACF and a the first $p$ significant lags of the PACF. Let's examine the ACF/PACF profiles of the same simulated AR(2) shown in Section 3, and check if the ACF/PACF explanation are refelcted in these plots. <li/>\n",
|
" <li> We are looking for a classical profiles for an AR(p) process such as an exponential decay of an ACF and a the first $p$ significant lags of the PACF. Let's examine the ACF/PACF profiles of the same simulated AR(2) shown in Section 3, and check if the ACF/PACF explanation are reflected in these plots. <li/>\n",
|
||||||
" <li><img src=\"figures/ACF_PACF_for_AR2.png\" class=\"img_class\">\n",
|
" <li><img src=\"figures/ACF_PACF_for_AR2.png\" class=\"img_class\">\n",
|
||||||
" <li> The autocorrelation coefficient for the 3rd lag is 0.6, which can be interpreted that a one unit increase in the value of the target varaible three periods ago leads to 0.6 units increase in the current period. However, the PACF plot shows that the partial autocorrealtion coefficient is zero (from a statistical point of view since it lies within the shaded region). This is happening because the 1st and 2nd lags are good predictors of the target variable. Ommiting these two lags from the regression results in the misleading conclusion that the third lag is a good prediciton. <li/>\n",
|
" <li> The autocorrelation coefficient for the 3rd lag is 0.6, which can be interpreted that a one unit increase in the value of the target variable three periods ago leads to 0.6 units increase in the current period. However, the PACF plot shows that the partial autocorrelation coefficient is zero (from a statistical point of view since it lies within the shaded region). This is happening because the 1st and 2nd lags are good predictors of the target variable. Omitting these two lags from the regression results in the misleading conclusion that the third lag is a good prediction. <li/>\n",
|
||||||
" <br/>\n",
|
" <br/>\n",
|
||||||
" <li> This is why it is important to examine both the ACF and the PACF plots when tring to determine the auto regressive order for the variable in question. <li/>\n",
|
" <li> This is why it is important to examine both the ACF and the PACF plots when trying to determine the auto regressive order for the variable in question. <li/>\n",
|
||||||
" </ul>\n",
|
" </ul>\n",
|
||||||
"</ul> "
|
"</ul> "
|
||||||
]
|
]
|
||||||
@@ -471,6 +478,9 @@
|
|||||||
"name": "vlbejan"
|
"name": "vlbejan"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"kernel_info": {
|
||||||
|
"name": "python38-azureml"
|
||||||
|
},
|
||||||
"kernelspec": {
|
"kernelspec": {
|
||||||
"display_name": "Python 3.8 - AzureML",
|
"display_name": "Python 3.8 - AzureML",
|
||||||
"language": "python",
|
"language": "python",
|
||||||
@@ -486,7 +496,15 @@
|
|||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.6.9"
|
"version": "3.8.10"
|
||||||
|
},
|
||||||
|
"microsoft": {
|
||||||
|
"ms_spell_check": {
|
||||||
|
"ms_spell_check_language": "en"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nteract": {
|
||||||
|
"version": "nteract-front-end@1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nbformat": 4,
|
"nbformat": 4,
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-forecasting-univariate-recipe-experiment-settings
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -16,6 +16,13 @@
|
|||||||
""
|
""
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"<font color=\"red\" size=\"5\"><strong>!Important!</strong> </br>This notebook is outdated and is not supported by the AutoML Team. Please use the supported version ([link](https://github.com/Azure/azureml-examples/tree/main/sdk/python/jobs/automl-standalone-jobs/automl-forecasting-recipes-univariate)).</font>"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
@@ -300,27 +307,14 @@
|
|||||||
"df_train.to_csv(\"train.csv\", index=False)\n",
|
"df_train.to_csv(\"train.csv\", index=False)\n",
|
||||||
"df_test.to_csv(\"test.csv\", index=False)\n",
|
"df_test.to_csv(\"test.csv\", index=False)\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
"from azureml.data.dataset_factory import TabularDatasetFactory\n",
|
||||||
|
"\n",
|
||||||
"datastore = ws.get_default_datastore()\n",
|
"datastore = ws.get_default_datastore()\n",
|
||||||
"datastore.upload_files(\n",
|
"train_dataset = TabularDatasetFactory.register_pandas_dataframe(\n",
|
||||||
" files=[\"./train.csv\"],\n",
|
" df_train, target=(datastore, \"dataset/\"), name=\"train\"\n",
|
||||||
" target_path=\"uni-recipe-dataset/tabular/\",\n",
|
|
||||||
" overwrite=True,\n",
|
|
||||||
" show_progress=True,\n",
|
|
||||||
")\n",
|
")\n",
|
||||||
"datastore.upload_files(\n",
|
"test_dataset = TabularDatasetFactory.register_pandas_dataframe(\n",
|
||||||
" files=[\"./test.csv\"],\n",
|
" df_test, target=(datastore, \"dataset/\"), name=\"test\"\n",
|
||||||
" target_path=\"uni-recipe-dataset/tabular/\",\n",
|
|
||||||
" overwrite=True,\n",
|
|
||||||
" show_progress=True,\n",
|
|
||||||
")\n",
|
|
||||||
"\n",
|
|
||||||
"from azureml.core import Dataset\n",
|
|
||||||
"\n",
|
|
||||||
"train_dataset = Dataset.Tabular.from_delimited_files(\n",
|
|
||||||
" path=[(datastore, \"uni-recipe-dataset/tabular/train.csv\")]\n",
|
|
||||||
")\n",
|
|
||||||
"test_dataset = Dataset.Tabular.from_delimited_files(\n",
|
|
||||||
" path=[(datastore, \"uni-recipe-dataset/tabular/test.csv\")]\n",
|
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# print the first 5 rows of the Dataset\n",
|
"# print the first 5 rows of the Dataset\n",
|
||||||
@@ -571,6 +565,9 @@
|
|||||||
"name": "vlbejan"
|
"name": "vlbejan"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"kernel_info": {
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
"kernelspec": {
|
"kernelspec": {
|
||||||
"display_name": "Python 3.8 - AzureML",
|
"display_name": "Python 3.8 - AzureML",
|
||||||
"language": "python",
|
"language": "python",
|
||||||
@@ -586,7 +583,15 @@
|
|||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.8.5"
|
"version": "3.8.10"
|
||||||
|
},
|
||||||
|
"microsoft": {
|
||||||
|
"ms_spell_check": {
|
||||||
|
"ms_spell_check_language": "en"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nteract": {
|
||||||
|
"version": "nteract-front-end@1.0.0"
|
||||||
},
|
},
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"interpreter": {
|
"interpreter": {
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-forecasting-univariate-recipe-run-experiment
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -7,7 +7,7 @@ compute instance.
|
|||||||
import argparse
|
import argparse
|
||||||
from azureml.core import Dataset, Run
|
from azureml.core import Dataset, Run
|
||||||
from azureml.automl.core.shared.constants import TimeSeriesInternal
|
from azureml.automl.core.shared.constants import TimeSeriesInternal
|
||||||
from sklearn.externals import joblib
|
import joblib
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
|||||||
@@ -1,5 +1,21 @@
|
|||||||
{
|
{
|
||||||
"cells": [
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
||||||
|
"\n",
|
||||||
|
"Licensed under the MIT License."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
@@ -554,273 +570,6 @@
|
|||||||
"automl_run.upload_file(\"outputs/scoring_explainer.pkl\", scoring_explainer_file_name)"
|
"automl_run.upload_file(\"outputs/scoring_explainer.pkl\", scoring_explainer_file_name)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Deploying the scoring and explainer models to a web service to Azure Kubernetes Service (AKS)\n",
|
|
||||||
"\n",
|
|
||||||
"We use the TreeScoringExplainer from azureml.interpret package to create the scoring explainer which will be used to compute the raw and engineered feature importances at the inference time. In the cell below, we register the AutoML model and the scoring explainer with the Model Management Service."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Register trained automl model present in the 'outputs' folder in the artifacts\n",
|
|
||||||
"original_model = automl_run.register_model(\n",
|
|
||||||
" model_name=\"automl_model\", model_path=\"outputs/model.pkl\"\n",
|
|
||||||
")\n",
|
|
||||||
"scoring_explainer_model = automl_run.register_model(\n",
|
|
||||||
" model_name=\"scoring_explainer\", model_path=\"outputs/scoring_explainer.pkl\"\n",
|
|
||||||
")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Create the conda dependencies for setting up the service\n",
|
|
||||||
"\n",
|
|
||||||
"We need to download the conda dependencies using the automl_run object."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.automl.core.shared import constants\n",
|
|
||||||
"from azureml.core.environment import Environment\n",
|
|
||||||
"\n",
|
|
||||||
"automl_run.download_file(constants.CONDA_ENV_FILE_PATH, \"myenv.yml\")\n",
|
|
||||||
"myenv = Environment.from_conda_specification(name=\"myenv\", file_path=\"myenv.yml\")\n",
|
|
||||||
"myenv"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Write the Entry Script\n",
|
|
||||||
"Write the script that will be used to predict on your model"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%writefile score.py\n",
|
|
||||||
"import joblib\n",
|
|
||||||
"import pandas as pd\n",
|
|
||||||
"from azureml.core.model import Model\n",
|
|
||||||
"from azureml.train.automl.runtime.automl_explain_utilities import (\n",
|
|
||||||
" automl_setup_model_explanations,\n",
|
|
||||||
")\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def init():\n",
|
|
||||||
" global automl_model\n",
|
|
||||||
" global scoring_explainer\n",
|
|
||||||
"\n",
|
|
||||||
" # Retrieve the path to the model file using the model name\n",
|
|
||||||
" # Assume original model is named original_prediction_model\n",
|
|
||||||
" automl_model_path = Model.get_model_path(\"automl_model\")\n",
|
|
||||||
" scoring_explainer_path = Model.get_model_path(\"scoring_explainer\")\n",
|
|
||||||
"\n",
|
|
||||||
" automl_model = joblib.load(automl_model_path)\n",
|
|
||||||
" scoring_explainer = joblib.load(scoring_explainer_path)\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def run(raw_data):\n",
|
|
||||||
" data = pd.read_json(raw_data, orient=\"records\")\n",
|
|
||||||
" # Make prediction\n",
|
|
||||||
" predictions = automl_model.predict(data)\n",
|
|
||||||
" # Setup for inferencing explanations\n",
|
|
||||||
" automl_explainer_setup_obj = automl_setup_model_explanations(\n",
|
|
||||||
" automl_model, X_test=data, task=\"classification\"\n",
|
|
||||||
" )\n",
|
|
||||||
" # Retrieve model explanations for engineered explanations\n",
|
|
||||||
" engineered_local_importance_values = scoring_explainer.explain(\n",
|
|
||||||
" automl_explainer_setup_obj.X_test_transform\n",
|
|
||||||
" )\n",
|
|
||||||
" # Retrieve model explanations for raw explanations\n",
|
|
||||||
" raw_local_importance_values = scoring_explainer.explain(\n",
|
|
||||||
" automl_explainer_setup_obj.X_test_transform, get_raw=True\n",
|
|
||||||
" )\n",
|
|
||||||
" # You can return any data type as long as it is JSON-serializable\n",
|
|
||||||
" return {\n",
|
|
||||||
" \"predictions\": predictions.tolist(),\n",
|
|
||||||
" \"engineered_local_importance_values\": engineered_local_importance_values,\n",
|
|
||||||
" \"raw_local_importance_values\": raw_local_importance_values,\n",
|
|
||||||
" }"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Create the InferenceConfig \n",
|
|
||||||
"Create the inference config that will be used when deploying the model"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import InferenceConfig\n",
|
|
||||||
"\n",
|
|
||||||
"inf_config = InferenceConfig(entry_script=\"score.py\", environment=myenv)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Provision the AKS Cluster\n",
|
|
||||||
"This is a one time setup. You can reuse this cluster for multiple deployments after it has been created. If you delete the cluster or the resource group that contains it, then you would have to recreate it."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.compute import ComputeTarget, AksCompute\n",
|
|
||||||
"from azureml.core.compute_target import ComputeTargetException\n",
|
|
||||||
"\n",
|
|
||||||
"# Choose a name for your cluster.\n",
|
|
||||||
"aks_name = \"scoring-explain\"\n",
|
|
||||||
"\n",
|
|
||||||
"# Verify that cluster does not exist already\n",
|
|
||||||
"try:\n",
|
|
||||||
" aks_target = ComputeTarget(workspace=ws, name=aks_name)\n",
|
|
||||||
" print(\"Found existing cluster, use it.\")\n",
|
|
||||||
"except ComputeTargetException:\n",
|
|
||||||
" prov_config = AksCompute.provisioning_configuration(vm_size=\"STANDARD_D3_V2\")\n",
|
|
||||||
" aks_target = ComputeTarget.create(\n",
|
|
||||||
" workspace=ws, name=aks_name, provisioning_configuration=prov_config\n",
|
|
||||||
" )\n",
|
|
||||||
"aks_target.wait_for_completion(show_output=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Deploy web service to AKS"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Set the web service configuration (using default here)\n",
|
|
||||||
"from azureml.core.webservice import AksWebservice\n",
|
|
||||||
"from azureml.core.model import Model\n",
|
|
||||||
"\n",
|
|
||||||
"aks_config = AksWebservice.deploy_configuration()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"aks_service_name = \"model-scoring-local-aks\"\n",
|
|
||||||
"\n",
|
|
||||||
"aks_service = Model.deploy(\n",
|
|
||||||
" workspace=ws,\n",
|
|
||||||
" name=aks_service_name,\n",
|
|
||||||
" models=[scoring_explainer_model, original_model],\n",
|
|
||||||
" inference_config=inf_config,\n",
|
|
||||||
" deployment_config=aks_config,\n",
|
|
||||||
" deployment_target=aks_target,\n",
|
|
||||||
")\n",
|
|
||||||
"\n",
|
|
||||||
"aks_service.wait_for_deployment(show_output=True)\n",
|
|
||||||
"print(aks_service.state)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### View the service logs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"aks_service.get_logs()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Consume the web service using run method to do the scoring and explanation of scoring.\n",
|
|
||||||
"We test the web sevice by passing data. Run() method retrieves API keys behind the scenes to make sure that call is authenticated."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Serialize the first row of the test data into json\n",
|
|
||||||
"X_test_json = X_test_df[:1].to_json(orient=\"records\")\n",
|
|
||||||
"print(X_test_json)\n",
|
|
||||||
"\n",
|
|
||||||
"# Call the service to get the predictions and the engineered and raw explanations\n",
|
|
||||||
"output = aks_service.run(X_test_json)\n",
|
|
||||||
"\n",
|
|
||||||
"# Print the predicted value\n",
|
|
||||||
"print(\"predictions:\\n{}\\n\".format(output[\"predictions\"]))\n",
|
|
||||||
"# Print the engineered feature importances for the predicted value\n",
|
|
||||||
"print(\n",
|
|
||||||
" \"engineered_local_importance_values:\\n{}\\n\".format(\n",
|
|
||||||
" output[\"engineered_local_importance_values\"]\n",
|
|
||||||
" )\n",
|
|
||||||
")\n",
|
|
||||||
"# Print the raw feature importances for the predicted value\n",
|
|
||||||
"print(\n",
|
|
||||||
" \"raw_local_importance_values:\\n{}\\n\".format(output[\"raw_local_importance_values\"])\n",
|
|
||||||
")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Clean up\n",
|
|
||||||
"Delete the service."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"aks_service.delete()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-classification-credit-card-fraud-local
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -1,5 +1,27 @@
|
|||||||
{
|
{
|
||||||
"cells": [
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"hideCode": false,
|
||||||
|
"hidePrompt": false
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
||||||
|
"\n",
|
||||||
|
"Licensed under the MIT License."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {
|
||||||
|
"hideCode": false,
|
||||||
|
"hidePrompt": false
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
@@ -495,6 +517,30 @@
|
|||||||
"#### Create conda configuration for model explanations experiment from automl_run object"
|
"#### Create conda configuration for model explanations experiment from automl_run object"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import json\n",
|
||||||
|
"from azureml.core import Environment\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"def get_environment_safe(parent_run):\n",
|
||||||
|
" \"\"\"Get the environment from parent run\"\"\"\n",
|
||||||
|
" try:\n",
|
||||||
|
" return parent_run.get_environment()\n",
|
||||||
|
" except BaseException:\n",
|
||||||
|
" run_details = parent_run.get_details()\n",
|
||||||
|
" run_def = run_details.get(\"runDefinition\")\n",
|
||||||
|
" env = run_def.get(\"environment\")\n",
|
||||||
|
" if env is None:\n",
|
||||||
|
" raise\n",
|
||||||
|
" json.dump(env, open(\"azureml_environment.json\", \"w\"))\n",
|
||||||
|
" return Environment.load_from_directory(\".\")"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": null,
|
"execution_count": null,
|
||||||
@@ -502,8 +548,6 @@
|
|||||||
"outputs": [],
|
"outputs": [],
|
||||||
"source": [
|
"source": [
|
||||||
"from azureml.core.runconfig import RunConfiguration\n",
|
"from azureml.core.runconfig import RunConfiguration\n",
|
||||||
"from azureml.core.conda_dependencies import CondaDependencies\n",
|
|
||||||
"import pkg_resources\n",
|
|
||||||
"\n",
|
"\n",
|
||||||
"# create a new RunConfig object\n",
|
"# create a new RunConfig object\n",
|
||||||
"conda_run_config = RunConfiguration(framework=\"python\")\n",
|
"conda_run_config = RunConfiguration(framework=\"python\")\n",
|
||||||
@@ -513,7 +557,7 @@
|
|||||||
"conda_run_config.environment.docker.enabled = True\n",
|
"conda_run_config.environment.docker.enabled = True\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# specify CondaDependencies obj\n",
|
"# specify CondaDependencies obj\n",
|
||||||
"conda_run_config.environment = automl_run.get_environment()"
|
"conda_run_config.environment = get_environment_safe(automl_run)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -686,7 +730,7 @@
|
|||||||
" description=\"Get local explanations for Machine test data\",\n",
|
" description=\"Get local explanations for Machine test data\",\n",
|
||||||
")\n",
|
")\n",
|
||||||
"\n",
|
"\n",
|
||||||
"myenv = automl_run.get_environment()\n",
|
"myenv = get_environment_safe(automl_run)\n",
|
||||||
"inference_config = InferenceConfig(entry_script=\"score_explain.py\", environment=myenv)\n",
|
"inference_config = InferenceConfig(entry_script=\"score_explain.py\", environment=myenv)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# Use configs and models generated above\n",
|
"# Use configs and models generated above\n",
|
||||||
@@ -909,7 +953,7 @@
|
|||||||
"name": "python",
|
"name": "python",
|
||||||
"nbconvert_exporter": "python",
|
"nbconvert_exporter": "python",
|
||||||
"pygments_lexer": "ipython3",
|
"pygments_lexer": "ipython3",
|
||||||
"version": "3.6.7"
|
"version": "3.8.7"
|
||||||
},
|
},
|
||||||
"tags": [
|
"tags": [
|
||||||
"featurization",
|
"featurization",
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-regression-explanation-featurization
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -1,5 +1,21 @@
|
|||||||
{
|
{
|
||||||
"cells": [
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
||||||
|
"\n",
|
||||||
|
"Licensed under the MIT License."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
name: auto-ml-regression
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
|
|
||||||
NOTICES AND INFORMATION
|
|
||||||
Do Not Translate or Localize
|
|
||||||
|
|
||||||
This Azure Machine Learning service example notebooks repository includes material from the projects listed below.
|
|
||||||
|
|
||||||
|
|
||||||
1. SSD-Tensorflow (https://github.com/balancap/ssd-tensorflow)
|
|
||||||
|
|
||||||
|
|
||||||
%% SSD-Tensorflow NOTICES AND INFORMATION BEGIN HERE
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
=========================================
|
|
||||||
END OF SSD-Tensorflow NOTICES AND INFORMATION
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
|
|
||||||
# Notebooks for Microsoft Azure Machine Learning Hardware Accelerated Models SDK
|
|
||||||
|
|
||||||
Easily create and train a model using various deep neural networks (DNNs) as a featurizer for deployment to Azure or a Data Box Edge device for ultra-low latency inferencing using FPGA's. These models are currently available:
|
|
||||||
|
|
||||||
* ResNet 50
|
|
||||||
* ResNet 152
|
|
||||||
* DenseNet-121
|
|
||||||
* VGG-16
|
|
||||||
* SSD-VGG
|
|
||||||
|
|
||||||
To learn more about the azureml-accel-model classes, see the section [Model Classes](#model-classes) below or the [Azure ML Accel Models SDK documentation](https://docs.microsoft.com/en-us/python/api/azureml-accel-models/azureml.accel?view=azure-ml-py).
|
|
||||||
|
|
||||||
### Step 1: Create an Azure ML workspace
|
|
||||||
Follow [these instructions](https://docs.microsoft.com/en-us/azure/machine-learning/service/setup-create-workspace) to install the Azure ML SDK on your local machine, create an Azure ML workspace, and set up your notebook environment, which is required for the next step.
|
|
||||||
|
|
||||||
### Step 2: Check your FPGA quota
|
|
||||||
Use the Azure CLI to check whether you have quota.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
az vm list-usage --location "eastus" -o table
|
|
||||||
```
|
|
||||||
|
|
||||||
The other locations are ``southeastasia``, ``westeurope``, and ``westus2``.
|
|
||||||
|
|
||||||
Under the "Name" column, look for "Standard PBS Family vCPUs" and ensure you have at least 6 vCPUs under "CurrentValue."
|
|
||||||
|
|
||||||
If you do not have quota, then submit a request form [here](https://aka.ms/accelerateAI).
|
|
||||||
|
|
||||||
### Step 3: Install the Azure ML Accelerated Models SDK
|
|
||||||
Once you have set up your environment, install the Azure ML Accel Models SDK. This package requires tensorflow >= 1.6,<2.0 to be installed.
|
|
||||||
|
|
||||||
If you already have tensorflow >= 1.6,<2.0 installed in your development environment, you can install the SDK package using:
|
|
||||||
|
|
||||||
```
|
|
||||||
pip install azureml-accel-models
|
|
||||||
```
|
|
||||||
|
|
||||||
If you do not have tensorflow >= 1.6,<2.0 and are using a CPU-only development environment, our SDK with tensorflow can be installed using:
|
|
||||||
|
|
||||||
```
|
|
||||||
pip install azureml-accel-models[cpu]
|
|
||||||
```
|
|
||||||
|
|
||||||
If your machine supports GPU (for example, on an [Azure DSVM](https://docs.microsoft.com/en-us/azure/machine-learning/data-science-virtual-machine/overview)), then you can leverage the tensorflow-gpu functionality using:
|
|
||||||
|
|
||||||
```
|
|
||||||
pip install azureml-accel-models[gpu]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 4: Follow our notebooks
|
|
||||||
|
|
||||||
We provide notebooks to walk through the following scenarios, linked below:
|
|
||||||
* [Quickstart](https://github.com/Azure/MachineLearningNotebooks/blob/33d6def8c30d3dd3a5bfbea50b9c727788185faf/how-to-use-azureml/deployment/accelerated-models/accelerated-models-quickstart.ipynb), deploy and inference a ResNet50 model trained on ImageNet
|
|
||||||
* [Object Detection](https://github.com/Azure/MachineLearningNotebooks/blob/33d6def8c30d3dd3a5bfbea50b9c727788185faf/how-to-use-azureml/deployment/accelerated-models/accelerated-models-object-detection.ipynb), deploy and inference an SSD-VGG model that can do object detection
|
|
||||||
* [Training models](https://github.com/Azure/MachineLearningNotebooks/blob/33d6def8c30d3dd3a5bfbea50b9c727788185faf/how-to-use-azureml/deployment/accelerated-models/accelerated-models-training.ipynb), train one of our accelerated models on the Kaggle Cats and Dogs dataset to see how to improve accuracy on custom datasets
|
|
||||||
|
|
||||||
**Note**: the above notebooks work only for tensorflow >= 1.6,<2.0.
|
|
||||||
|
|
||||||
<a name="model-classes"></a>
|
|
||||||
## Model Classes
|
|
||||||
As stated above, we support 5 Accelerated Models. Here's more information on their input and output tensors.
|
|
||||||
|
|
||||||
**Available models and output tensors**
|
|
||||||
|
|
||||||
The available models and the corresponding default classifier output tensors are below. This is the value that you would use during inferencing if you used the default classifier.
|
|
||||||
* Resnet50, QuantizedResnet50
|
|
||||||
``
|
|
||||||
output_tensors = "classifier_1/resnet_v1_50/predictions/Softmax:0"
|
|
||||||
``
|
|
||||||
* Resnet152, QuantizedResnet152
|
|
||||||
``
|
|
||||||
output_tensors = "classifier/resnet_v1_152/predictions/Softmax:0"
|
|
||||||
``
|
|
||||||
* Densenet121, QuantizedDensenet121
|
|
||||||
``
|
|
||||||
output_tensors = "classifier/densenet121/predictions/Softmax:0"
|
|
||||||
``
|
|
||||||
* Vgg16, QuantizedVgg16
|
|
||||||
``
|
|
||||||
output_tensors = "classifier/vgg_16/fc8/squeezed:0"
|
|
||||||
``
|
|
||||||
* SsdVgg, QuantizedSsdVgg
|
|
||||||
``
|
|
||||||
output_tensors = ['ssd_300_vgg/block4_box/Reshape_1:0', 'ssd_300_vgg/block7_box/Reshape_1:0', 'ssd_300_vgg/block8_box/Reshape_1:0', 'ssd_300_vgg/block9_box/Reshape_1:0', 'ssd_300_vgg/block10_box/Reshape_1:0', 'ssd_300_vgg/block11_box/Reshape_1:0', 'ssd_300_vgg/block4_box/Reshape:0', 'ssd_300_vgg/block7_box/Reshape:0', 'ssd_300_vgg/block8_box/Reshape:0', 'ssd_300_vgg/block9_box/Reshape:0', 'ssd_300_vgg/block10_box/Reshape:0', 'ssd_300_vgg/block11_box/Reshape:0']
|
|
||||||
``
|
|
||||||
|
|
||||||
For more information, please reference the azureml.accel.models package in the [Azure ML Python SDK documentation](https://docs.microsoft.com/en-us/python/api/azureml-accel-models/azureml.accel.models?view=azure-ml-py).
|
|
||||||
|
|
||||||
**Input tensors**
|
|
||||||
|
|
||||||
The input_tensors value defaults to "Placeholder:0" and is created in the [Image Preprocessing](#construct-model) step in the line:
|
|
||||||
``
|
|
||||||
in_images = tf.placeholder(tf.string)
|
|
||||||
``
|
|
||||||
|
|
||||||
You can change the input_tensors name by doing this:
|
|
||||||
``
|
|
||||||
in_images = tf.placeholder(tf.string, name="images")
|
|
||||||
``
|
|
||||||
|
|
||||||
|
|
||||||
## Resources
|
|
||||||
* [Read more about FPGAs](https://docs.microsoft.com/en-us/azure/machine-learning/service/concept-accelerate-with-fpgas)
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
# Model Deployment with Azure ML service
|
|
||||||
You can use Azure Machine Learning to package, debug, validate and deploy inference containers to a variety of compute targets. This process is known as "MLOps" (ML operationalization).
|
|
||||||
For more information please check out this article: https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-deploy-and-where
|
|
||||||
|
|
||||||
## Get Started
|
|
||||||
To begin, you will need an ML workspace.
|
|
||||||
For more information please check out this article: https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-manage-workspace
|
|
||||||
|
|
||||||
## Deploy to the cloud
|
|
||||||
You can deploy to the cloud using the Azure ML CLI or the Azure ML SDK.
|
|
||||||
- CLI example: https://aka.ms/azmlcli
|
|
||||||
- Notebook example: [model-register-and-deploy](./model-register-and-deploy.ipynb).
|
|
||||||
|
|
||||||

|
|
||||||
@@ -1,395 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
|
||||||
"\n",
|
|
||||||
"Licensed under the MIT License."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Deploy Multiple Models as Webservice\n",
|
|
||||||
"\n",
|
|
||||||
"This example shows how to deploy a Webservice with multiple models in step-by-step fashion:\n",
|
|
||||||
"\n",
|
|
||||||
" 1. Register Models\n",
|
|
||||||
" 2. Deploy Models as Webservice"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Prerequisites\n",
|
|
||||||
"If you are using an Azure Machine Learning Notebook VM, you are all set. Otherwise, make sure you go through the [configuration](../../../configuration.ipynb) Notebook first if you haven't."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Check core SDK version number\n",
|
|
||||||
"import azureml.core\n",
|
|
||||||
"\n",
|
|
||||||
"print(\"SDK version:\", azureml.core.VERSION)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Initialize Workspace\n",
|
|
||||||
"\n",
|
|
||||||
"Initialize a workspace object from persisted configuration."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"create workspace"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Workspace\n",
|
|
||||||
"\n",
|
|
||||||
"ws = Workspace.from_config()\n",
|
|
||||||
"print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep='\\n')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Register Models"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"In this example, we will be using and registering two models. \n",
|
|
||||||
"\n",
|
|
||||||
"First we will train two simple models on the [diabetes dataset](https://scikit-learn.org/stable/datasets/toy_dataset.html#diabetes-dataset) included with scikit-learn, serializing them to files in the current directory."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import joblib\n",
|
|
||||||
"import sklearn\n",
|
|
||||||
"\n",
|
|
||||||
"from sklearn.datasets import load_diabetes\n",
|
|
||||||
"from sklearn.linear_model import BayesianRidge, Ridge\n",
|
|
||||||
"\n",
|
|
||||||
"x, y = load_diabetes(return_X_y=True)\n",
|
|
||||||
"\n",
|
|
||||||
"first_model = Ridge().fit(x, y)\n",
|
|
||||||
"second_model = BayesianRidge().fit(x, y)\n",
|
|
||||||
"\n",
|
|
||||||
"joblib.dump(first_model, \"first_model.pkl\")\n",
|
|
||||||
"joblib.dump(second_model, \"second_model.pkl\")\n",
|
|
||||||
"\n",
|
|
||||||
"print(\"Trained models using scikit-learn {}.\".format(sklearn.__version__))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Now that we have our trained models locally, we will register them as Models with the names `my_first_model` and `my_second_model` in the workspace."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"register model from file"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import Model\n",
|
|
||||||
"\n",
|
|
||||||
"my_model_1 = Model.register(model_path=\"first_model.pkl\",\n",
|
|
||||||
" model_name=\"my_first_model\",\n",
|
|
||||||
" workspace=ws)\n",
|
|
||||||
"\n",
|
|
||||||
"my_model_2 = Model.register(model_path=\"second_model.pkl\",\n",
|
|
||||||
" model_name=\"my_second_model\",\n",
|
|
||||||
" workspace=ws)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Write the Entry Script\n",
|
|
||||||
"Write the script that will be used to predict on your models"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Model.get_model_path()\n",
|
|
||||||
"\n",
|
|
||||||
"To get the paths of your models, use `Model.get_model_path(model_name, version=None, _workspace=None)` method. This method will find the path to a model using the name of the model registered under the workspace.\n",
|
|
||||||
"\n",
|
|
||||||
"In this example, we do not use the optional arguments `version` and `_workspace`.\n",
|
|
||||||
"\n",
|
|
||||||
"#### Using environment variable AZUREML_MODEL_DIR\n",
|
|
||||||
"\n",
|
|
||||||
"In other [examples](../deploy-to-cloud/score.py) with a single model deployment, we use the environment variable `AZUREML_MODEL_DIR` and model file name to get the model path. \n",
|
|
||||||
"\n",
|
|
||||||
"For single model deployments, this environment variable is the path to the model folder (`./azureml-models/$MODEL_NAME/$VERSION`). When we deploy multiple models, the environment variable is set to the folder containing all models (./azureml-models).\n",
|
|
||||||
"\n",
|
|
||||||
"If you're using multiple models and you know the versions of the models you deploy, you can use this method to get the model path:\n",
|
|
||||||
"\n",
|
|
||||||
"```python\n",
|
|
||||||
"# Construct the model path using the registered model name, version, and model file name\n",
|
|
||||||
"model_1_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'my_first_model', '1', 'first_model.pkl')\n",
|
|
||||||
"```"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%writefile score.py\n",
|
|
||||||
"import joblib\n",
|
|
||||||
"import json\n",
|
|
||||||
"import numpy as np\n",
|
|
||||||
"\n",
|
|
||||||
"from azureml.core.model import Model\n",
|
|
||||||
"\n",
|
|
||||||
"def init():\n",
|
|
||||||
" global model_1, model_2\n",
|
|
||||||
" # Here \"my_first_model\" is the name of the model registered under the workspace.\n",
|
|
||||||
" # This call will return the path to the .pkl file on the local disk.\n",
|
|
||||||
" model_1_path = Model.get_model_path(model_name='my_first_model')\n",
|
|
||||||
" model_2_path = Model.get_model_path(model_name='my_second_model')\n",
|
|
||||||
" \n",
|
|
||||||
" # Deserialize the model files back into scikit-learn models.\n",
|
|
||||||
" model_1 = joblib.load(model_1_path)\n",
|
|
||||||
" model_2 = joblib.load(model_2_path)\n",
|
|
||||||
"\n",
|
|
||||||
"# Note you can pass in multiple rows for scoring.\n",
|
|
||||||
"def run(raw_data):\n",
|
|
||||||
" try:\n",
|
|
||||||
" data = json.loads(raw_data)['data']\n",
|
|
||||||
" data = np.array(data)\n",
|
|
||||||
" \n",
|
|
||||||
" # Call predict() on each model\n",
|
|
||||||
" result_1 = model_1.predict(data)\n",
|
|
||||||
" result_2 = model_2.predict(data)\n",
|
|
||||||
"\n",
|
|
||||||
" # You can return any JSON-serializable value.\n",
|
|
||||||
" return {\"prediction1\": result_1.tolist(), \"prediction2\": result_2.tolist()}\n",
|
|
||||||
" except Exception as e:\n",
|
|
||||||
" result = str(e)\n",
|
|
||||||
" return result"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Create Environment"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"You can now create and/or use an Environment object when deploying a Webservice. The Environment can have been previously registered with your Workspace, or it will be registered with it as a part of the Webservice deployment. Please note that your environment must include azureml-defaults with verion >= 1.0.45 as a pip dependency, because it contains the functionality needed to host the model as a web service.\n",
|
|
||||||
"\n",
|
|
||||||
"More information can be found in our [using environments notebook](../training/using-environments/using-environments.ipynb)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Environment\n",
|
|
||||||
"\n",
|
|
||||||
"env = Environment(\"deploytocloudenv\")\n",
|
|
||||||
"env.python.conda_dependencies.add_pip_package(\"joblib\")\n",
|
|
||||||
"env.python.conda_dependencies.add_pip_package(\"numpy==1.23\")\n",
|
|
||||||
"env.python.conda_dependencies.add_pip_package(\"scikit-learn=={}\".format(sklearn.__version__))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Create Inference Configuration\n",
|
|
||||||
"\n",
|
|
||||||
"There is now support for a source directory, you can upload an entire folder from your local machine as dependencies for the Webservice.\n",
|
|
||||||
"Note: in that case, environments's entry_script and file_path are relative paths to the source_directory path; myenv.docker.base_dockerfile is a string containing extra docker steps or contents of the docker file.\n",
|
|
||||||
"\n",
|
|
||||||
"Sample code for using a source directory:\n",
|
|
||||||
"\n",
|
|
||||||
"```python\n",
|
|
||||||
"from azureml.core.environment import Environment\n",
|
|
||||||
"from azureml.core.model import InferenceConfig\n",
|
|
||||||
"\n",
|
|
||||||
"myenv = Environment.from_conda_specification(name='myenv', file_path='env/myenv.yml')\n",
|
|
||||||
"\n",
|
|
||||||
"# explicitly set base_image to None when setting base_dockerfile\n",
|
|
||||||
"myenv.docker.base_image = None\n",
|
|
||||||
"# add extra docker commends to execute\n",
|
|
||||||
"myenv.docker.base_dockerfile = \"FROM ubuntu\\n RUN echo \\\"hello\\\"\"\n",
|
|
||||||
"\n",
|
|
||||||
"inference_config = InferenceConfig(source_directory=\"C:/abc\",\n",
|
|
||||||
" entry_script=\"x/y/score.py\",\n",
|
|
||||||
" environment=myenv)\n",
|
|
||||||
"```\n",
|
|
||||||
"\n",
|
|
||||||
" - file_path: input parameter to Environment constructor. Manages conda and python package dependencies.\n",
|
|
||||||
" - env.docker.base_dockerfile: any extra steps you want to inject into docker file\n",
|
|
||||||
" - source_directory: holds source path as string, this entire folder gets added in image so its really easy to access any files within this folder or subfolder\n",
|
|
||||||
" - entry_script: contains logic specific to initializing your model and running predictions"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"create image"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import InferenceConfig\n",
|
|
||||||
"\n",
|
|
||||||
"inference_config = InferenceConfig(entry_script=\"score.py\", environment=env)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Deploy Model as Webservice on Azure Container Instance\n",
|
|
||||||
"\n",
|
|
||||||
"Note that the service creation can take few minutes."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"azuremlexception-remarks-sample"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.webservice import AciWebservice\n",
|
|
||||||
"\n",
|
|
||||||
"aci_service_name = \"aciservice-multimodel\"\n",
|
|
||||||
"\n",
|
|
||||||
"deployment_config = AciWebservice.deploy_configuration(cpu_cores=1, memory_gb=1)\n",
|
|
||||||
"\n",
|
|
||||||
"service = Model.deploy(ws, aci_service_name, [my_model_1, my_model_2], inference_config, deployment_config, overwrite=True)\n",
|
|
||||||
"service.wait_for_deployment(True)\n",
|
|
||||||
"\n",
|
|
||||||
"print(service.state)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Test web service"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import json\n",
|
|
||||||
"\n",
|
|
||||||
"test_sample = json.dumps({'data': x[0:2].tolist()})\n",
|
|
||||||
"\n",
|
|
||||||
"prediction = service.run(test_sample)\n",
|
|
||||||
"\n",
|
|
||||||
"print(prediction)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Delete ACI to clean up"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"deploy service",
|
|
||||||
"aci"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"service.delete()"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "jenns"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3.8 - AzureML",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python38-azureml"
|
|
||||||
},
|
|
||||||
"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.6.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
name: multi-model-register-and-deploy
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
- numpy
|
|
||||||
- scikit-learn
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# Model Deployment with Azure ML service
|
|
||||||
You can use Azure Machine Learning to package, debug, validate and deploy inference containers to a variety of compute targets. This process is known as "MLOps" (ML operationalization).
|
|
||||||
For more information please check out this article: https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-deploy-and-where
|
|
||||||
|
|
||||||
## Get Started
|
|
||||||
To begin, you will need an ML workspace.
|
|
||||||
For more information please check out this article: https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-manage-workspace
|
|
||||||
|
|
||||||
## Deploy to the cloud
|
|
||||||
You can deploy to the cloud using the Azure ML CLI or the Azure ML SDK.
|
|
||||||
- CLI example: https://aka.ms/azmlcli
|
|
||||||
- Notebook example: [model-register-and-deploy](./model-register-and-deploy.ipynb).
|
|
||||||
@@ -1,597 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
|
||||||
"\n",
|
|
||||||
"Licensed under the MIT License."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Register model and deploy as webservice in ACI\n",
|
|
||||||
"\n",
|
|
||||||
"Following this notebook, you will:\n",
|
|
||||||
"\n",
|
|
||||||
" - Learn how to register a model in your Azure Machine Learning Workspace.\n",
|
|
||||||
" - Deploy your model as a web service in an Azure Container Instance."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Prerequisites\n",
|
|
||||||
"\n",
|
|
||||||
"If you are using an Azure Machine Learning Notebook VM, you are all set. Otherwise, make sure you go through the [configuration notebook](../../../configuration.ipynb) to install the Azure Machine Learning Python SDK and create a workspace."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import azureml.core\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# Check core SDK version number.\n",
|
|
||||||
"print('SDK version:', azureml.core.VERSION)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Initialize workspace\n",
|
|
||||||
"\n",
|
|
||||||
"Create a [Workspace](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.workspace%28class%29?view=azure-ml-py) object from your persisted configuration."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"create workspace"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Workspace\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"ws = Workspace.from_config()\n",
|
|
||||||
"print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep='\\n')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Create trained model\n",
|
|
||||||
"\n",
|
|
||||||
"For this example, we will train a small model on scikit-learn's [diabetes dataset](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_diabetes.html). "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import joblib\n",
|
|
||||||
"\n",
|
|
||||||
"from sklearn.datasets import load_diabetes\n",
|
|
||||||
"from sklearn.linear_model import Ridge\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"dataset_x, dataset_y = load_diabetes(return_X_y=True)\n",
|
|
||||||
"\n",
|
|
||||||
"model = Ridge().fit(dataset_x, dataset_y)\n",
|
|
||||||
"\n",
|
|
||||||
"joblib.dump(model, 'sklearn_regression_model.pkl')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Register input and output datasets\n",
|
|
||||||
"\n",
|
|
||||||
"Here, you will register the data used to create the model in your workspace."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import numpy as np\n",
|
|
||||||
"\n",
|
|
||||||
"from azureml.core import Dataset\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"np.savetxt('features.csv', dataset_x, delimiter=',')\n",
|
|
||||||
"np.savetxt('labels.csv', dataset_y, delimiter=',')\n",
|
|
||||||
"\n",
|
|
||||||
"datastore = ws.get_default_datastore()\n",
|
|
||||||
"datastore.upload_files(files=['./features.csv', './labels.csv'],\n",
|
|
||||||
" target_path='sklearn_regression/',\n",
|
|
||||||
" overwrite=True)\n",
|
|
||||||
"\n",
|
|
||||||
"input_dataset = Dataset.Tabular.from_delimited_files(path=[(datastore, 'sklearn_regression/features.csv')])\n",
|
|
||||||
"output_dataset = Dataset.Tabular.from_delimited_files(path=[(datastore, 'sklearn_regression/labels.csv')])"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Register model\n",
|
|
||||||
"\n",
|
|
||||||
"Register a file or folder as a model by calling [Model.register()](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.model.model?view=azure-ml-py#register-workspace--model-path--model-name--tags-none--properties-none--description-none--datasets-none--model-framework-none--model-framework-version-none--child-paths-none-).\n",
|
|
||||||
"\n",
|
|
||||||
"In addition to the content of the model file itself, your registered model will also store model metadata -- model description, tags, and framework information -- that will be useful when managing and deploying models in your workspace. Using tags, for instance, you can categorize your models and apply filters when listing models in your workspace. Also, marking this model with the scikit-learn framework will simplify deploying it as a web service, as we'll see later."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"register model from file",
|
|
||||||
"sample-model-register"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import sklearn\n",
|
|
||||||
"\n",
|
|
||||||
"from azureml.core import Model\n",
|
|
||||||
"from azureml.core.resource_configuration import ResourceConfiguration\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"model = Model.register(workspace=ws,\n",
|
|
||||||
" model_name='my-sklearn-model', # Name of the registered model in your workspace.\n",
|
|
||||||
" model_path='./sklearn_regression_model.pkl', # Local file to upload and register as a model.\n",
|
|
||||||
" model_framework=Model.Framework.SCIKITLEARN, # Framework used to create the model.\n",
|
|
||||||
" model_framework_version=sklearn.__version__, # Version of scikit-learn used to create the model.\n",
|
|
||||||
" sample_input_dataset=input_dataset,\n",
|
|
||||||
" sample_output_dataset=output_dataset,\n",
|
|
||||||
" resource_configuration=ResourceConfiguration(cpu=1, memory_in_gb=0.5),\n",
|
|
||||||
" description='Ridge regression model to predict diabetes progression.',\n",
|
|
||||||
" tags={'area': 'diabetes', 'type': 'regression'})\n",
|
|
||||||
"\n",
|
|
||||||
"print('Name:', model.name)\n",
|
|
||||||
"print('Version:', model.version)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Deploy model\n",
|
|
||||||
"\n",
|
|
||||||
"Deploy your model as a web service using [Model.deploy()](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.model.model?view=azure-ml-py#deploy-workspace--name--models--inference-config--deployment-config-none--deployment-target-none-). Web services take one or more models, load them in an environment, and run them on one of several supported deployment targets. For more information on all your options when deploying models, see the [next steps](#Next-steps) section at the end of this notebook.\n",
|
|
||||||
"\n",
|
|
||||||
"For this example, we will deploy your scikit-learn model to an Azure Container Instance (ACI)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Use a default environment (for supported models)\n",
|
|
||||||
"\n",
|
|
||||||
"The Azure Machine Learning service provides a default environment for supported model frameworks, including scikit-learn, based on the metadata you provided when registering your model. This is the easiest way to deploy your model.\n",
|
|
||||||
"\n",
|
|
||||||
"Even when you deploy your model to ACI with a default environment you can still customize the deploy configuration (i.e. the number of cores and amount of memory made available for the deployment) using the [AciWebservice.deploy_configuration()](https://docs.microsoft.com/python/api/azureml-core/azureml.core.webservice.aci.aciwebservice#deploy-configuration-cpu-cores-none--memory-gb-none--tags-none--properties-none--description-none--location-none--auth-enabled-none--ssl-enabled-none--enable-app-insights-none--ssl-cert-pem-file-none--ssl-key-pem-file-none--ssl-cname-none--dns-name-label-none--). Look at the \"Use a custom environment\" section of this notebook for more information on deploy configuration.\n",
|
|
||||||
"\n",
|
|
||||||
"**Note**: This step can take several minutes."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"service_name = 'my-sklearn-service'\n",
|
|
||||||
"\n",
|
|
||||||
"service = Model.deploy(ws, service_name, [model], overwrite=True)\n",
|
|
||||||
"service.wait_for_deployment(show_output=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"After your model is deployed, perform a call to the web service using [service.run()](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.webservice%28class%29?view=azure-ml-py#run-input-)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import json\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"input_payload = json.dumps({\n",
|
|
||||||
" 'data': dataset_x[0:2].tolist(),\n",
|
|
||||||
" 'method': 'predict' # If you have a classification model, you can get probabilities by changing this to 'predict_proba'.\n",
|
|
||||||
"})\n",
|
|
||||||
"\n",
|
|
||||||
"output = service.run(input_payload)\n",
|
|
||||||
"\n",
|
|
||||||
"print(output)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"When you are finished testing your service, clean up the deployment with [service.delete()](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.webservice%28class%29?view=azure-ml-py#delete--)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"service.delete()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Use a custom environment\n",
|
|
||||||
"\n",
|
|
||||||
"If you want more control over how your model is run, if it uses another framework, or if it has special runtime requirements, you can instead specify your own environment and scoring method. Custom environments can be used for any model you want to deploy.\n",
|
|
||||||
"\n",
|
|
||||||
"Specify the model's runtime environment by creating an [Environment](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.environment%28class%29?view=azure-ml-py) object and providing the [CondaDependencies](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.conda_dependencies.condadependencies?view=azure-ml-py) needed by your model."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Environment\n",
|
|
||||||
"from azureml.core.conda_dependencies import CondaDependencies\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"environment = Environment('my-sklearn-environment')\n",
|
|
||||||
"environment.python.conda_dependencies = CondaDependencies.create(conda_packages=[\n",
|
|
||||||
" 'pip==20.2.4'],\n",
|
|
||||||
" pip_packages=[\n",
|
|
||||||
" 'azureml-defaults',\n",
|
|
||||||
" 'inference-schema[numpy-support]',\n",
|
|
||||||
" 'joblib',\n",
|
|
||||||
" 'numpy==1.23',\n",
|
|
||||||
" 'scikit-learn=={}'.format(sklearn.__version__)\n",
|
|
||||||
"])"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"When using a custom environment, you must also provide Python code for initializing and running your model. An example script is included with this notebook."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"with open('score.py') as f:\n",
|
|
||||||
" print(f.read())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Deploy your model in the custom environment by providing an [InferenceConfig](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.model.inferenceconfig?view=azure-ml-py) object to [Model.deploy()](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.model.model?view=azure-ml-py#deploy-workspace--name--models--inference-config--deployment-config-none--deployment-target-none-). In this case we are also using the [AciWebservice.deploy_configuration()](https://docs.microsoft.com/python/api/azureml-core/azureml.core.webservice.aci.aciwebservice#deploy-configuration-cpu-cores-none--memory-gb-none--tags-none--properties-none--description-none--location-none--auth-enabled-none--ssl-enabled-none--enable-app-insights-none--ssl-cert-pem-file-none--ssl-key-pem-file-none--ssl-cname-none--dns-name-label-none--) method to generate a custom deploy configuration.\n",
|
|
||||||
"\n",
|
|
||||||
"**Note**: This step can take several minutes."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"azuremlexception-remarks-sample",
|
|
||||||
"sample-aciwebservice-deploy-config"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import InferenceConfig\n",
|
|
||||||
"from azureml.core.webservice import AciWebservice\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"service_name = 'my-custom-env-service'\n",
|
|
||||||
"\n",
|
|
||||||
"inference_config = InferenceConfig(entry_script='score.py', environment=environment)\n",
|
|
||||||
"aci_config = AciWebservice.deploy_configuration(cpu_cores=1, memory_gb=1)\n",
|
|
||||||
"\n",
|
|
||||||
"service = Model.deploy(workspace=ws,\n",
|
|
||||||
" name=service_name,\n",
|
|
||||||
" models=[model],\n",
|
|
||||||
" inference_config=inference_config,\n",
|
|
||||||
" deployment_config=aci_config,\n",
|
|
||||||
" overwrite=True)\n",
|
|
||||||
"service.wait_for_deployment(show_output=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"After your model is deployed, make a call to the web service using [service.run()](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.webservice%28class%29?view=azure-ml-py#run-input-)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"input_payload = json.dumps({\n",
|
|
||||||
" 'data': dataset_x[0:2].tolist()\n",
|
|
||||||
"})\n",
|
|
||||||
"\n",
|
|
||||||
"output = service.run(input_payload)\n",
|
|
||||||
"\n",
|
|
||||||
"print(output)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"When you are finished testing your service, clean up the deployment with [service.delete()](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.webservice%28class%29?view=azure-ml-py#delete--)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"service.delete()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Model Profiling\n",
|
|
||||||
"\n",
|
|
||||||
"Profile your model to understand how much CPU and memory the service, created as a result of its deployment, will need. Profiling returns information such as CPU usage, memory usage, and response latency. It also provides a CPU and memory recommendation based on the resource usage. You can profile your model (or more precisely the service built based on your model) on any CPU and/or memory combination where 0.1 <= CPU <= 3.5 and 0.1GB <= memory <= 15GB. If you do not provide a CPU and/or memory requirement, we will test it on the default configuration of 3.5 CPU and 15GB memory.\n",
|
|
||||||
"\n",
|
|
||||||
"In order to profile your model you will need:\n",
|
|
||||||
"- a registered model\n",
|
|
||||||
"- an entry script\n",
|
|
||||||
"- an inference configuration\n",
|
|
||||||
"- a single column tabular dataset, where each row contains a string representing sample request data sent to the service.\n",
|
|
||||||
"\n",
|
|
||||||
"Please, note that profiling is a long running operation and can take up to 25 minutes depending on the size of the dataset.\n",
|
|
||||||
"\n",
|
|
||||||
"At this point we only support profiling of services that expect their request data to be a string, for example: string serialized json, text, string serialized image, etc. The content of each row of the dataset (string) will be put into the body of the HTTP request and sent to the service encapsulating the model for scoring.\n",
|
|
||||||
"\n",
|
|
||||||
"Below is an example of how you can construct an input dataset to profile a service which expects its incoming requests to contain serialized json. In this case we created a dataset based one hundred instances of the same request data. In real world scenarios however, we suggest that you use larger datasets with various inputs, especially if your model resource usage/behavior is input dependent."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"You may want to register datasets using the register() method to your workspace so they can be shared with others, reused and referred to by name in your script.\n",
|
|
||||||
"You can try get the dataset first to see if it's already registered."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Datastore\n",
|
|
||||||
"from azureml.core.dataset import Dataset\n",
|
|
||||||
"from azureml.data import dataset_type_definitions\n",
|
|
||||||
"\n",
|
|
||||||
"dataset_name='diabetes_sample_request_data'\n",
|
|
||||||
"\n",
|
|
||||||
"dataset_registered = False\n",
|
|
||||||
"try:\n",
|
|
||||||
" sample_request_data = Dataset.get_by_name(workspace = ws, name = dataset_name)\n",
|
|
||||||
" dataset_registered = True\n",
|
|
||||||
"except:\n",
|
|
||||||
" print(\"The dataset {} is not registered in workspace yet.\".format(dataset_name))\n",
|
|
||||||
"\n",
|
|
||||||
"if not dataset_registered:\n",
|
|
||||||
" # create a string that can be utf-8 encoded and\n",
|
|
||||||
" # put in the body of the request\n",
|
|
||||||
" serialized_input_json = json.dumps({\n",
|
|
||||||
" 'data': [\n",
|
|
||||||
" [ 0.03807591, 0.05068012, 0.06169621, 0.02187235, -0.0442235,\n",
|
|
||||||
" -0.03482076, -0.04340085, -0.00259226, 0.01990842, -0.01764613]\n",
|
|
||||||
" ]\n",
|
|
||||||
" })\n",
|
|
||||||
" dataset_content = []\n",
|
|
||||||
" for i in range(100):\n",
|
|
||||||
" dataset_content.append(serialized_input_json)\n",
|
|
||||||
" dataset_content = '\\n'.join(dataset_content)\n",
|
|
||||||
" file_name = \"{}.txt\".format(dataset_name)\n",
|
|
||||||
" f = open(file_name, 'w')\n",
|
|
||||||
" f.write(dataset_content)\n",
|
|
||||||
" f.close()\n",
|
|
||||||
"\n",
|
|
||||||
" # upload the txt file created above to the Datastore and create a dataset from it\n",
|
|
||||||
" data_store = Datastore.get_default(ws)\n",
|
|
||||||
" data_store.upload_files(['./' + file_name], target_path='sample_request_data')\n",
|
|
||||||
" datastore_path = [(data_store, 'sample_request_data' +'/' + file_name)]\n",
|
|
||||||
" sample_request_data = Dataset.Tabular.from_delimited_files(\n",
|
|
||||||
" datastore_path,\n",
|
|
||||||
" separator='\\n',\n",
|
|
||||||
" infer_column_types=True,\n",
|
|
||||||
" header=dataset_type_definitions.PromoteHeadersBehavior.NO_HEADERS)\n",
|
|
||||||
" sample_request_data = sample_request_data.register(workspace=ws,\n",
|
|
||||||
" name=dataset_name,\n",
|
|
||||||
" create_new_version=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Now that we have an input dataset we are ready to go ahead with profiling. In this case we are testing the previously introduced sklearn regression model on 1 CPU and 0.5 GB memory. The memory usage and recommendation presented in the result is measured in Gigabytes. The CPU usage and recommendation is measured in CPU cores."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from datetime import datetime\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"environment = Environment('my-sklearn-environment')\n",
|
|
||||||
"environment.python.conda_dependencies = CondaDependencies.create(conda_packages=[\n",
|
|
||||||
" 'pip==20.2.4'],\n",
|
|
||||||
" pip_packages=[\n",
|
|
||||||
" 'azureml-defaults',\n",
|
|
||||||
" 'inference-schema[numpy-support]',\n",
|
|
||||||
" 'joblib',\n",
|
|
||||||
" 'numpy==1.23',\n",
|
|
||||||
" 'scikit-learn=={}'.format(sklearn.__version__)\n",
|
|
||||||
"])\n",
|
|
||||||
"inference_config = InferenceConfig(entry_script='score.py', environment=environment)\n",
|
|
||||||
"# if cpu and memory_in_gb parameters are not provided\n",
|
|
||||||
"# the model will be profiled on default configuration of\n",
|
|
||||||
"# 3.5CPU and 15GB memory\n",
|
|
||||||
"profile = Model.profile(ws,\n",
|
|
||||||
" 'rgrsn-%s' % datetime.now().strftime('%m%d%Y-%H%M%S'),\n",
|
|
||||||
" [model],\n",
|
|
||||||
" inference_config,\n",
|
|
||||||
" input_dataset=sample_request_data,\n",
|
|
||||||
" cpu=1.0,\n",
|
|
||||||
" memory_in_gb=0.5)\n",
|
|
||||||
"\n",
|
|
||||||
"# profiling is a long running operation and may take up to 25 min\n",
|
|
||||||
"profile.wait_for_completion(True)\n",
|
|
||||||
"details = profile.get_details()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Model packaging\n",
|
|
||||||
"\n",
|
|
||||||
"If you want to build a Docker image that encapsulates your model and its dependencies, you can use the model packaging option. The output image will be pushed to your workspace's ACR.\n",
|
|
||||||
"\n",
|
|
||||||
"You must include an Environment object in your inference configuration to use `Model.package()`.\n",
|
|
||||||
"\n",
|
|
||||||
"```python\n",
|
|
||||||
"package = Model.package(ws, [model], inference_config)\n",
|
|
||||||
"package.wait_for_creation(show_output=True) # Or show_output=False to hide the Docker build logs.\n",
|
|
||||||
"package.pull()\n",
|
|
||||||
"```\n",
|
|
||||||
"\n",
|
|
||||||
"Instead of a fully-built image, you can also generate a Dockerfile and download all the assets needed to build an image on top of your Environment.\n",
|
|
||||||
"\n",
|
|
||||||
"```python\n",
|
|
||||||
"package = Model.package(ws, [model], inference_config, generate_dockerfile=True)\n",
|
|
||||||
"package.wait_for_creation(show_output=True)\n",
|
|
||||||
"package.save(\"./local_context_dir\")\n",
|
|
||||||
"```"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Next steps\n",
|
|
||||||
"\n",
|
|
||||||
" - To run a production-ready web service, see the [notebook on deployment to Azure Kubernetes Service](../production-deploy-to-aks/production-deploy-to-aks.ipynb).\n",
|
|
||||||
" - To run a local web service, see the [notebook on deployment to a local Docker container](../deploy-to-local/register-model-deploy-local.ipynb).\n",
|
|
||||||
" - For more information on datasets, see the [notebook on training with datasets](../../work-with-data/datasets-tutorial/train-with-datasets/train-with-datasets.ipynb).\n",
|
|
||||||
" - For more information on environments, see the [notebook on using environments](../../training/using-environments/using-environments.ipynb).\n",
|
|
||||||
" - For information on all the available deployment targets, see [“How and where to deploy models”](https://docs.microsoft.com/azure/machine-learning/v1/how-to-deploy-and-where#choose-a-compute-target)."
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "vaidyas"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"category": "deployment",
|
|
||||||
"compute": [
|
|
||||||
"None"
|
|
||||||
],
|
|
||||||
"datasets": [
|
|
||||||
"Diabetes"
|
|
||||||
],
|
|
||||||
"deployment": [
|
|
||||||
"Azure Container Instance"
|
|
||||||
],
|
|
||||||
"exclude_from_index": false,
|
|
||||||
"framework": [
|
|
||||||
"Scikit-learn"
|
|
||||||
],
|
|
||||||
"friendly_name": "Register model and deploy as webservice",
|
|
||||||
"index_order": 3,
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3.8 - AzureML",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python38-azureml"
|
|
||||||
},
|
|
||||||
"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.7.0"
|
|
||||||
},
|
|
||||||
"star_tag": [
|
|
||||||
"featured"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"None"
|
|
||||||
],
|
|
||||||
"task": "Deploy a model with Azure Machine Learning"
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
name: model-register-and-deploy
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
- numpy
|
|
||||||
- scikit-learn
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
import joblib
|
|
||||||
import numpy as np
|
|
||||||
import os
|
|
||||||
|
|
||||||
from inference_schema.schema_decorators import input_schema, output_schema
|
|
||||||
from inference_schema.parameter_types.numpy_parameter_type import NumpyParameterType
|
|
||||||
|
|
||||||
|
|
||||||
# The init() method is called once, when the web service starts up.
|
|
||||||
#
|
|
||||||
# Typically you would deserialize the model file, as shown here using joblib,
|
|
||||||
# and store it in a global variable so your run() method can access it later.
|
|
||||||
def init():
|
|
||||||
global model
|
|
||||||
|
|
||||||
# The AZUREML_MODEL_DIR environment variable indicates
|
|
||||||
# a directory containing the model file you registered.
|
|
||||||
model_filename = 'sklearn_regression_model.pkl'
|
|
||||||
model_path = os.path.join(os.environ['AZUREML_MODEL_DIR'], model_filename)
|
|
||||||
|
|
||||||
model = joblib.load(model_path)
|
|
||||||
|
|
||||||
|
|
||||||
# The run() method is called each time a request is made to the scoring API.
|
|
||||||
#
|
|
||||||
# Shown here are the optional input_schema and output_schema decorators
|
|
||||||
# from the inference-schema pip package. Using these decorators on your
|
|
||||||
# run() method parses and validates the incoming payload against
|
|
||||||
# the example input you provide here. This will also generate a Swagger
|
|
||||||
# API document for your web service.
|
|
||||||
@input_schema('data', NumpyParameterType(np.array([[0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0]])))
|
|
||||||
@output_schema(NumpyParameterType(np.array([4429.929236457418])))
|
|
||||||
def run(data):
|
|
||||||
# Use the model object loaded by init().
|
|
||||||
result = model.predict(data)
|
|
||||||
|
|
||||||
# You can return any JSON-serializable object.
|
|
||||||
return result.tolist()
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# Model Deployment with Azure ML service
|
|
||||||
You can use Azure Machine Learning to package, debug, validate and deploy inference containers to a variety of compute targets. This process is known as "MLOps" (ML operationalization).
|
|
||||||
For more information please check out this article: https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-deploy-and-where
|
|
||||||
|
|
||||||
## Get Started
|
|
||||||
To begin, you will need an ML workspace.
|
|
||||||
For more information please check out this article: https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-manage-workspace
|
|
||||||
|
|
||||||
## Deploy locally
|
|
||||||
You can deploy a model locally for testing & debugging using the Azure ML CLI or the Azure ML SDK.
|
|
||||||
- CLI example: https://aka.ms/azmlcli
|
|
||||||
- Notebook example: [register-model-deploy-local](./register-model-deploy-local.ipynb).
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
RUN echo "this is test"
|
|
||||||
@@ -1,495 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
|
||||||
"\n",
|
|
||||||
"Licensed under the MIT License."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Register model and deploy locally with advanced usages\n",
|
|
||||||
"\n",
|
|
||||||
"This example shows how to deploy a web service in step-by-step fashion:\n",
|
|
||||||
"\n",
|
|
||||||
" 1. Register model\n",
|
|
||||||
" 2. Deploy the image as a web service in a local Docker container.\n",
|
|
||||||
" 3. Quickly test changes to your entry script by reloading the local service.\n",
|
|
||||||
" 4. Optionally, you can also make changes to model, conda or extra_docker_file_steps and update local service"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Prerequisites\n",
|
|
||||||
"If you are using an Azure Machine Learning Notebook VM, you are all set. Otherwise, make sure you go through the [configuration](../../../configuration.ipynb) Notebook first if you haven't."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Check core SDK version number\n",
|
|
||||||
"import azureml.core\n",
|
|
||||||
"\n",
|
|
||||||
"print(\"SDK version:\", azureml.core.VERSION)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Initialize Workspace\n",
|
|
||||||
"\n",
|
|
||||||
"Initialize a workspace object from persisted configuration."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"create workspace"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Workspace\n",
|
|
||||||
"\n",
|
|
||||||
"ws = Workspace.from_config()\n",
|
|
||||||
"print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep='\\n')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Create trained model\n",
|
|
||||||
"\n",
|
|
||||||
"For this example, we will train a small model on scikit-learn's [diabetes dataset](https://scikit-learn.org/stable/datasets/toy_dataset.html#diabetes-dataset). "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import joblib\n",
|
|
||||||
"\n",
|
|
||||||
"from sklearn.datasets import load_diabetes\n",
|
|
||||||
"from sklearn.linear_model import Ridge\n",
|
|
||||||
"\n",
|
|
||||||
"dataset_x, dataset_y = load_diabetes(return_X_y=True)\n",
|
|
||||||
"\n",
|
|
||||||
"sk_model = Ridge().fit(dataset_x, dataset_y)\n",
|
|
||||||
"\n",
|
|
||||||
"joblib.dump(sk_model, \"sklearn_regression_model.pkl\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Register Model"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"You can add tags and descriptions to your models. we are using `sklearn_regression_model.pkl` file in the current directory as a model with the name `sklearn_regression_model` in the workspace.\n",
|
|
||||||
"\n",
|
|
||||||
"Using tags, you can track useful information such as the name and version of the machine learning library used to train the model, framework, category, target customer etc. Note that tags must be alphanumeric."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"register model from file",
|
|
||||||
"sample-model-register"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import Model\n",
|
|
||||||
"\n",
|
|
||||||
"model = Model.register(model_path=\"sklearn_regression_model.pkl\",\n",
|
|
||||||
" model_name=\"sklearn_regression_model\",\n",
|
|
||||||
" tags={'area': \"diabetes\", 'type': \"regression\"},\n",
|
|
||||||
" description=\"Ridge regression model to predict diabetes\",\n",
|
|
||||||
" workspace=ws)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Manage your dependencies in a folder"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import os\n",
|
|
||||||
"\n",
|
|
||||||
"source_directory = \"source_directory\"\n",
|
|
||||||
"\n",
|
|
||||||
"os.makedirs(source_directory, exist_ok=True)\n",
|
|
||||||
"os.makedirs(os.path.join(source_directory, \"x/y\"), exist_ok=True)\n",
|
|
||||||
"os.makedirs(os.path.join(source_directory, \"env\"), exist_ok=True)\n",
|
|
||||||
"os.makedirs(os.path.join(source_directory, \"dockerstep\"), exist_ok=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Show `score.py`. "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%writefile source_directory/x/y/score.py\n",
|
|
||||||
"import joblib\n",
|
|
||||||
"import json\n",
|
|
||||||
"import numpy as np\n",
|
|
||||||
"import os\n",
|
|
||||||
"\n",
|
|
||||||
"from inference_schema.schema_decorators import input_schema, output_schema\n",
|
|
||||||
"from inference_schema.parameter_types.numpy_parameter_type import NumpyParameterType\n",
|
|
||||||
"\n",
|
|
||||||
"def init():\n",
|
|
||||||
" global model\n",
|
|
||||||
" # AZUREML_MODEL_DIR is an environment variable created during deployment. Join this path with the filename of the model file.\n",
|
|
||||||
" # It holds the path to the directory that contains the deployed model (./azureml-models/$MODEL_NAME/$VERSION)\n",
|
|
||||||
" # If there are multiple models, this value is the path to the directory containing all deployed models (./azureml-models)\n",
|
|
||||||
" model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'sklearn_regression_model.pkl')\n",
|
|
||||||
" # Deserialize the model file back into a sklearn model.\n",
|
|
||||||
" model = joblib.load(model_path)\n",
|
|
||||||
"\n",
|
|
||||||
" global name\n",
|
|
||||||
" # Note here, the entire source directory from inference config gets added into image.\n",
|
|
||||||
" # Below is an example of how you can use any extra files in image.\n",
|
|
||||||
" with open('./source_directory/extradata.json') as json_file:\n",
|
|
||||||
" data = json.load(json_file)\n",
|
|
||||||
" name = data[\"people\"][0][\"name\"]\n",
|
|
||||||
"\n",
|
|
||||||
"input_sample = np.array([[10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0]])\n",
|
|
||||||
"output_sample = np.array([3726.995])\n",
|
|
||||||
"\n",
|
|
||||||
"@input_schema('data', NumpyParameterType(input_sample))\n",
|
|
||||||
"@output_schema(NumpyParameterType(output_sample))\n",
|
|
||||||
"def run(data):\n",
|
|
||||||
" try:\n",
|
|
||||||
" result = model.predict(data)\n",
|
|
||||||
" # You can return any JSON-serializable object.\n",
|
|
||||||
" return \"Hello \" + name + \" here is your result = \" + str(result)\n",
|
|
||||||
" except Exception as e:\n",
|
|
||||||
" error = str(e)\n",
|
|
||||||
" return error"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%writefile source_directory/extradata.json\n",
|
|
||||||
"{\n",
|
|
||||||
" \"people\": [\n",
|
|
||||||
" {\n",
|
|
||||||
" \"website\": \"microsoft.com\", \n",
|
|
||||||
" \"from\": \"Seattle\", \n",
|
|
||||||
" \"name\": \"Mrudula\"\n",
|
|
||||||
" }\n",
|
|
||||||
" ]\n",
|
|
||||||
"}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Create Inference Configuration\n",
|
|
||||||
"\n",
|
|
||||||
" - file_path: input parameter to Environment constructor. Manages conda and python package dependencies.\n",
|
|
||||||
" - env.docker.base_dockerfile: any extra steps you want to inject into docker file\n",
|
|
||||||
" - source_directory: holds source path as string, this entire folder gets added in image so its really easy to access any files within this folder or subfolder\n",
|
|
||||||
" - entry_script: contains logic specific to initializing your model and running predictions"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import sklearn\n",
|
|
||||||
"\n",
|
|
||||||
"from azureml.core.environment import Environment\n",
|
|
||||||
"from azureml.core.model import InferenceConfig\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"myenv = Environment('myenv')\n",
|
|
||||||
"myenv.python.conda_dependencies.add_pip_package(\"inference-schema[numpy-support]\")\n",
|
|
||||||
"myenv.python.conda_dependencies.add_pip_package(\"joblib\")\n",
|
|
||||||
"myenv.python.conda_dependencies.add_pip_package(\"scikit-learn=={}\".format(sklearn.__version__))\n",
|
|
||||||
"\n",
|
|
||||||
"# explicitly set base_image to None when setting base_dockerfile\n",
|
|
||||||
"myenv.docker.base_image = None\n",
|
|
||||||
"myenv.docker.base_dockerfile = \"FROM mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04\\nRUN echo \\\"this is test\\\"\"\n",
|
|
||||||
"myenv.inferencing_stack_version = \"latest\"\n",
|
|
||||||
"\n",
|
|
||||||
"inference_config = InferenceConfig(source_directory=source_directory,\n",
|
|
||||||
" entry_script=\"x/y/score.py\",\n",
|
|
||||||
" environment=myenv)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Deploy Model as a Local Docker Web Service\n",
|
|
||||||
"\n",
|
|
||||||
"*Make sure you have Docker installed and running.*\n",
|
|
||||||
"\n",
|
|
||||||
"Note that the service creation can take few minutes.\n",
|
|
||||||
"\n",
|
|
||||||
"NOTE:\n",
|
|
||||||
"\n",
|
|
||||||
"The Docker image runs as a Linux container. If you are running Docker for Windows, you need to ensure the Linux Engine is running:\n",
|
|
||||||
"\n",
|
|
||||||
" # PowerShell command to switch to Linux engine\n",
|
|
||||||
" & 'C:\\Program Files\\Docker\\Docker\\DockerCli.exe' -SwitchLinuxEngine"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"deploy service",
|
|
||||||
"aci"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.webservice import LocalWebservice\n",
|
|
||||||
"\n",
|
|
||||||
"# This is optional, if not provided Docker will choose a random unused port.\n",
|
|
||||||
"deployment_config = LocalWebservice.deploy_configuration(port=6789)\n",
|
|
||||||
"\n",
|
|
||||||
"local_service = Model.deploy(ws, \"test\", [model], inference_config, deployment_config)\n",
|
|
||||||
"\n",
|
|
||||||
"local_service.wait_for_deployment()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"print('Local service port: {}'.format(local_service.port))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Check Status and Get Container Logs\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"print(local_service.get_logs())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Test Web Service"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Call the web service with some input data to get a prediction."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import json\n",
|
|
||||||
"\n",
|
|
||||||
"sample_input = json.dumps({\n",
|
|
||||||
" 'data': dataset_x[0:2].tolist()\n",
|
|
||||||
"})\n",
|
|
||||||
"\n",
|
|
||||||
"print(local_service.run(sample_input))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Reload Service\n",
|
|
||||||
"\n",
|
|
||||||
"You can update your score.py file and then call `reload()` to quickly restart the service. This will only reload your execution script and dependency files, it will not rebuild the underlying Docker image. As a result, `reload()` is fast, but if you do need to rebuild the image -- to add a new Conda or pip package, for instance -- you will have to call `update()`, instead (see below)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%writefile source_directory/x/y/score.py\n",
|
|
||||||
"import joblib\n",
|
|
||||||
"import json\n",
|
|
||||||
"import numpy as np\n",
|
|
||||||
"import os\n",
|
|
||||||
"\n",
|
|
||||||
"from inference_schema.schema_decorators import input_schema, output_schema\n",
|
|
||||||
"from inference_schema.parameter_types.numpy_parameter_type import NumpyParameterType\n",
|
|
||||||
"\n",
|
|
||||||
"def init():\n",
|
|
||||||
" global model\n",
|
|
||||||
" # AZUREML_MODEL_DIR is an environment variable created during deployment.\n",
|
|
||||||
" # It is the path to the model folder (./azureml-models/$MODEL_NAME/$VERSION)\n",
|
|
||||||
" # For multiple models, it points to the folder containing all deployed models (./azureml-models)\n",
|
|
||||||
" model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'sklearn_regression_model.pkl')\n",
|
|
||||||
" # Deserialize the model file back into a sklearn model.\n",
|
|
||||||
" model = joblib.load(model_path)\n",
|
|
||||||
"\n",
|
|
||||||
" global name, from_location\n",
|
|
||||||
" # Note here, the entire source directory from inference config gets added into image.\n",
|
|
||||||
" # Below is an example of how you can use any extra files in image.\n",
|
|
||||||
" with open('source_directory/extradata.json') as json_file: \n",
|
|
||||||
" data = json.load(json_file)\n",
|
|
||||||
" name = data[\"people\"][0][\"name\"]\n",
|
|
||||||
" from_location = data[\"people\"][0][\"from\"]\n",
|
|
||||||
"\n",
|
|
||||||
"input_sample = np.array([[10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0]])\n",
|
|
||||||
"output_sample = np.array([3726.995])\n",
|
|
||||||
"\n",
|
|
||||||
"@input_schema('data', NumpyParameterType(input_sample))\n",
|
|
||||||
"@output_schema(NumpyParameterType(output_sample))\n",
|
|
||||||
"def run(data):\n",
|
|
||||||
" try:\n",
|
|
||||||
" result = model.predict(data)\n",
|
|
||||||
" # You can return any JSON-serializable object.\n",
|
|
||||||
" return \"Hello \" + name + \" from \" + from_location + \" here is your result = \" + str(result)\n",
|
|
||||||
" except Exception as e:\n",
|
|
||||||
" error = str(e)\n",
|
|
||||||
" return error"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"local_service.reload()\n",
|
|
||||||
"print(\"--------------------------------------------------------------\")\n",
|
|
||||||
"\n",
|
|
||||||
"# After calling reload(), run() will return the updated message.\n",
|
|
||||||
"local_service.run(sample_input)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Update Service\n",
|
|
||||||
"\n",
|
|
||||||
"If you want to change your model(s), Conda dependencies, or deployment configuration, call `update()` to rebuild the Docker image.\n",
|
|
||||||
"\n",
|
|
||||||
"```python\n",
|
|
||||||
"\n",
|
|
||||||
"local_service.update(models=[SomeOtherModelObject],\n",
|
|
||||||
" deployment_config=local_config,\n",
|
|
||||||
" inference_config=inference_config)\n",
|
|
||||||
"```"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Delete Service"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"local_service.delete()"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "keriehm"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3.8 - AzureML",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python38-azureml"
|
|
||||||
},
|
|
||||||
"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.6.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
@@ -1,556 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
|
||||||
"\n",
|
|
||||||
"Licensed under the MIT License."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Register model and deploy locally\n",
|
|
||||||
"\n",
|
|
||||||
"This example shows how to deploy a web service in step-by-step fashion:\n",
|
|
||||||
"\n",
|
|
||||||
" 1. Register model\n",
|
|
||||||
" 2. Deploy the image as a web service in a local Docker container.\n",
|
|
||||||
" 3. Quickly test changes to your entry script by reloading the local service.\n",
|
|
||||||
" 4. Optionally, you can also make changes to model, conda or extra_docker_file_steps and update local service"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Prerequisites\n",
|
|
||||||
"If you are using an Azure Machine Learning Notebook VM, you are all set. Otherwise, make sure you go through the [configuration](../../../configuration.ipynb) Notebook first if you haven't."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Check core SDK version number\n",
|
|
||||||
"import azureml.core\n",
|
|
||||||
"\n",
|
|
||||||
"print(\"SDK version:\", azureml.core.VERSION)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Initialize Workspace\n",
|
|
||||||
"\n",
|
|
||||||
"Initialize a workspace object from persisted configuration."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Workspace\n",
|
|
||||||
"\n",
|
|
||||||
"ws = Workspace.from_config()\n",
|
|
||||||
"print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep='\\n')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Create trained model\n",
|
|
||||||
"\n",
|
|
||||||
"For this example, we will train a small model on scikit-learn's [diabetes dataset](https://scikit-learn.org/stable/datasets/toy_dataset.html#diabetes-dataset). "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import joblib\n",
|
|
||||||
"\n",
|
|
||||||
"from sklearn.datasets import load_diabetes\n",
|
|
||||||
"from sklearn.linear_model import Ridge\n",
|
|
||||||
"\n",
|
|
||||||
"dataset_x, dataset_y = load_diabetes(return_X_y=True)\n",
|
|
||||||
"\n",
|
|
||||||
"sk_model = Ridge().fit(dataset_x, dataset_y)\n",
|
|
||||||
"\n",
|
|
||||||
"joblib.dump(sk_model, \"sklearn_regression_model.pkl\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Register Model"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Here we are registering the serialized file `sklearn_regression_model.pkl` in the current directory as a model with the name `sklearn_regression_model` in the workspace.\n",
|
|
||||||
"\n",
|
|
||||||
"You can add tags and descriptions to your models. Using tags, you can track useful information such as the name and version of the machine learning library used to train the model, framework, category, target customer etc. Note that tags must be alphanumeric."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"register model from file"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import Model\n",
|
|
||||||
"\n",
|
|
||||||
"model = Model.register(model_path=\"sklearn_regression_model.pkl\",\n",
|
|
||||||
" model_name=\"sklearn_regression_model\",\n",
|
|
||||||
" tags={'area': \"diabetes\", 'type': \"regression\"},\n",
|
|
||||||
" description=\"Ridge regression model to predict diabetes\",\n",
|
|
||||||
" workspace=ws)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Create Environment"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import sklearn\n",
|
|
||||||
"\n",
|
|
||||||
"from azureml.core.environment import Environment\n",
|
|
||||||
"\n",
|
|
||||||
"environment = Environment(\"LocalDeploy\")\n",
|
|
||||||
"environment.python.conda_dependencies.add_pip_package(\"inference-schema[numpy-support]\")\n",
|
|
||||||
"environment.python.conda_dependencies.add_pip_package(\"joblib\")\n",
|
|
||||||
"environment.python.conda_dependencies.add_pip_package(\"scikit-learn=={}\".format(sklearn.__version__))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Provide the Scoring Script\n",
|
|
||||||
"\n",
|
|
||||||
"This Python script handles the model execution inside the service container. The `init()` method loads the model file, and `run(data)` is called for every input to the service."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%writefile score.py\n",
|
|
||||||
"import joblib\n",
|
|
||||||
"import json\n",
|
|
||||||
"import numpy as np\n",
|
|
||||||
"import os\n",
|
|
||||||
"\n",
|
|
||||||
"from inference_schema.schema_decorators import input_schema, output_schema\n",
|
|
||||||
"from inference_schema.parameter_types.numpy_parameter_type import NumpyParameterType\n",
|
|
||||||
"\n",
|
|
||||||
"def init():\n",
|
|
||||||
" global model\n",
|
|
||||||
" # AZUREML_MODEL_DIR is an environment variable created during deployment.\n",
|
|
||||||
" # It is the path to the model folder (./azureml-models/$MODEL_NAME/$VERSION)\n",
|
|
||||||
" # For multiple models, it points to the folder containing all deployed models (./azureml-models)\n",
|
|
||||||
" model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'sklearn_regression_model.pkl')\n",
|
|
||||||
" # Deserialize the model file back into a sklearn model.\n",
|
|
||||||
" model = joblib.load(model_path)\n",
|
|
||||||
"\n",
|
|
||||||
"input_sample = np.array([[10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0]])\n",
|
|
||||||
"output_sample = np.array([3726.995])\n",
|
|
||||||
"\n",
|
|
||||||
"@input_schema('data', NumpyParameterType(input_sample))\n",
|
|
||||||
"@output_schema(NumpyParameterType(output_sample))\n",
|
|
||||||
"def run(data):\n",
|
|
||||||
" try:\n",
|
|
||||||
" result = model.predict(data)\n",
|
|
||||||
" # You can return any JSON-serializable object.\n",
|
|
||||||
" return result.tolist()\n",
|
|
||||||
" except Exception as e:\n",
|
|
||||||
" error = str(e)\n",
|
|
||||||
" return error"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Create Inference Configuration"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import InferenceConfig\n",
|
|
||||||
"\n",
|
|
||||||
"inference_config = InferenceConfig(entry_script=\"score.py\",\n",
|
|
||||||
" environment=environment)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Deploy Model as a Local Docker Web Service\n",
|
|
||||||
"\n",
|
|
||||||
"*Make sure you have Docker installed and running.*\n",
|
|
||||||
"\n",
|
|
||||||
"Note that the service creation can take few minutes.\n",
|
|
||||||
"\n",
|
|
||||||
"NOTE:\n",
|
|
||||||
"\n",
|
|
||||||
"The Docker image runs as a Linux container. If you are running Docker for Windows, you need to ensure the Linux Engine is running:\n",
|
|
||||||
"\n",
|
|
||||||
" # PowerShell command to switch to Linux engine\n",
|
|
||||||
" & 'C:\\Program Files\\Docker\\Docker\\DockerCli.exe' -SwitchLinuxEngine"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"sample-localwebservice-deploy"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.webservice import LocalWebservice\n",
|
|
||||||
"\n",
|
|
||||||
"# This is optional, if not provided Docker will choose a random unused port.\n",
|
|
||||||
"deployment_config = LocalWebservice.deploy_configuration(port=6789)\n",
|
|
||||||
"\n",
|
|
||||||
"local_service = Model.deploy(ws, \"test\", [model], inference_config, deployment_config)\n",
|
|
||||||
"\n",
|
|
||||||
"local_service.wait_for_deployment()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"print('Local service port: {}'.format(local_service.port))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Check Status and Get Container Logs\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"print(local_service.get_logs())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Test Web Service"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Call the web service with some input data to get a prediction."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import json\n",
|
|
||||||
"\n",
|
|
||||||
"sample_input = json.dumps({\n",
|
|
||||||
" 'data': dataset_x[0:2].tolist()\n",
|
|
||||||
"})\n",
|
|
||||||
"\n",
|
|
||||||
"local_service.run(sample_input)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Reload Service\n",
|
|
||||||
"\n",
|
|
||||||
"You can update your score.py file and then call `reload()` to quickly restart the service. This will only reload your execution script and dependency files, it will not rebuild the underlying Docker image. As a result, `reload()` is fast, but if you do need to rebuild the image -- to add a new Conda or pip package, for instance -- you will have to call `update()`, instead (see below)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%writefile score.py\n",
|
|
||||||
"import joblib\n",
|
|
||||||
"import json\n",
|
|
||||||
"import numpy as np\n",
|
|
||||||
"import os\n",
|
|
||||||
"\n",
|
|
||||||
"from inference_schema.schema_decorators import input_schema, output_schema\n",
|
|
||||||
"from inference_schema.parameter_types.numpy_parameter_type import NumpyParameterType\n",
|
|
||||||
"\n",
|
|
||||||
"def init():\n",
|
|
||||||
" global model\n",
|
|
||||||
" # AZUREML_MODEL_DIR is an environment variable created during deployment.\n",
|
|
||||||
" # It is the path to the model folder (./azureml-models/$MODEL_NAME/$VERSION)\n",
|
|
||||||
" # For multiple models, it points to the folder containing all deployed models (./azureml-models)\n",
|
|
||||||
" model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'sklearn_regression_model.pkl')\n",
|
|
||||||
" # Deserialize the model file back into a sklearn model.\n",
|
|
||||||
" model = joblib.load(model_path)\n",
|
|
||||||
"\n",
|
|
||||||
"input_sample = np.array([[10.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0]])\n",
|
|
||||||
"output_sample = np.array([3726.995])\n",
|
|
||||||
"\n",
|
|
||||||
"@input_schema('data', NumpyParameterType(input_sample))\n",
|
|
||||||
"@output_schema(NumpyParameterType(output_sample))\n",
|
|
||||||
"def run(data):\n",
|
|
||||||
" try:\n",
|
|
||||||
" result = model.predict(data)\n",
|
|
||||||
" # You can return any JSON-serializable object.\n",
|
|
||||||
" return 'Hello from the updated score.py: ' + str(result.tolist())\n",
|
|
||||||
" except Exception as e:\n",
|
|
||||||
" error = str(e)\n",
|
|
||||||
" return error"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"local_service.reload()\n",
|
|
||||||
"print(\"--------------------------------------------------------------\")\n",
|
|
||||||
"\n",
|
|
||||||
"# After calling reload(), run() will return the updated message.\n",
|
|
||||||
"local_service.run(sample_input)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Update Service\n",
|
|
||||||
"\n",
|
|
||||||
"If you want to change your model(s), Conda dependencies or deployment configuration, call `update()` to rebuild the Docker image.\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"local_service.update(models=[model],\n",
|
|
||||||
" inference_config=inference_config,\n",
|
|
||||||
" deployment_config=deployment_config)\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Deploy model to AKS cluster based on the LocalWebservice's configuration."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# This is a one time setup for AKS Cluster. You can reuse this cluster for multiple deployments after it has been created. If you delete the cluster or the resource group that contains it, then you would have to recreate it.\n",
|
|
||||||
"from azureml.core.compute import AksCompute, ComputeTarget\n",
|
|
||||||
"from azureml.core.compute_target import ComputeTargetException\n",
|
|
||||||
"\n",
|
|
||||||
"# Choose a name for your AKS cluster\n",
|
|
||||||
"aks_name = 'my-aks-9' \n",
|
|
||||||
"\n",
|
|
||||||
"# Verify the cluster does not exist already\n",
|
|
||||||
"try:\n",
|
|
||||||
" aks_target = ComputeTarget(workspace=ws, name=aks_name)\n",
|
|
||||||
" print('Found existing cluster, use it.')\n",
|
|
||||||
"except ComputeTargetException:\n",
|
|
||||||
" # Use the default configuration (can also provide parameters to customize)\n",
|
|
||||||
" prov_config = AksCompute.provisioning_configuration()\n",
|
|
||||||
"\n",
|
|
||||||
" # Create the cluster\n",
|
|
||||||
" aks_target = ComputeTarget.create(workspace = ws, \n",
|
|
||||||
" name = aks_name, \n",
|
|
||||||
" provisioning_configuration = prov_config)\n",
|
|
||||||
"\n",
|
|
||||||
"if aks_target.get_status() != \"Succeeded\":\n",
|
|
||||||
" aks_target.wait_for_completion(show_output=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.webservice import AksWebservice\n",
|
|
||||||
"# Set the web service configuration (using default here)\n",
|
|
||||||
"aks_config = AksWebservice.deploy_configuration()\n",
|
|
||||||
"\n",
|
|
||||||
"# # Enable token auth and disable (key) auth on the webservice\n",
|
|
||||||
"# aks_config = AksWebservice.deploy_configuration(token_auth_enabled=True, auth_enabled=False)\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%time\n",
|
|
||||||
"aks_service_name ='aks-service-1'\n",
|
|
||||||
"\n",
|
|
||||||
"aks_service = local_service.deploy_to_cloud(name=aks_service_name,\n",
|
|
||||||
" deployment_config=aks_config,\n",
|
|
||||||
" deployment_target=aks_target)\n",
|
|
||||||
"\n",
|
|
||||||
"aks_service.wait_for_deployment(show_output = True)\n",
|
|
||||||
"print(aks_service.state)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Test aks service\n",
|
|
||||||
"\n",
|
|
||||||
"sample_input = json.dumps({\n",
|
|
||||||
" 'data': dataset_x[0:2].tolist()\n",
|
|
||||||
"})\n",
|
|
||||||
"\n",
|
|
||||||
"aks_service.run(sample_input)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Delete the service if not needed.\n",
|
|
||||||
"aks_service.delete()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Delete Service"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"local_service.delete()"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "keriehm"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"category": "tutorial",
|
|
||||||
"compute": [
|
|
||||||
"Local"
|
|
||||||
],
|
|
||||||
"datasets": [
|
|
||||||
"None"
|
|
||||||
],
|
|
||||||
"deployment": [
|
|
||||||
"Local"
|
|
||||||
],
|
|
||||||
"exclude_from_index": false,
|
|
||||||
"framework": [
|
|
||||||
"None"
|
|
||||||
],
|
|
||||||
"friendly_name": "Register a model and deploy locally",
|
|
||||||
"index_order": 1,
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3.8 - AzureML",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python38-azureml"
|
|
||||||
},
|
|
||||||
"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.6.8"
|
|
||||||
},
|
|
||||||
"star_tag": [],
|
|
||||||
"tags": [
|
|
||||||
"None"
|
|
||||||
],
|
|
||||||
"task": "Deployment"
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
@@ -1,373 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
|
||||||
"\n",
|
|
||||||
"Licensed under the MIT License."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Deploy models to Azure Kubernetes Service (AKS) using controlled roll out\n",
|
|
||||||
"This notebook will show you how to deploy mulitple AKS webservices with the same scoring endpoint and how to roll out your models in a controlled manner by configuring % of scoring traffic going to each webservice. If you are using a Notebook VM, you are all set. Otherwise, go through the [configuration notebook](../../../configuration.ipynb) to install the Azure Machine Learning Python SDK and create an Azure ML Workspace."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Check for latest version\n",
|
|
||||||
"import azureml.core\n",
|
|
||||||
"print(azureml.core.VERSION)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Initialize workspace\n",
|
|
||||||
"Create a [Workspace](https://docs.microsoft.com/python/api/azureml-core/azureml.core.workspace%28class%29?view=azure-ml-py) object from your persisted configuration."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.workspace import Workspace\n",
|
|
||||||
"\n",
|
|
||||||
"ws = Workspace.from_config()\n",
|
|
||||||
"print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep = '\\n')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Register the model\n",
|
|
||||||
"Register a file or folder as a model by calling [Model.register()](https://docs.microsoft.com/python/api/azureml-core/azureml.core.model.model?view=azure-ml-py#register-workspace--model-path--model-name--tags-none--properties-none--description-none--datasets-none--model-framework-none--model-framework-version-none--child-paths-none-).\n",
|
|
||||||
"In addition to the content of the model file itself, your registered model will also store model metadata -- model description, tags, and framework information -- that will be useful when managing and deploying models in your workspace. Using tags, for instance, you can categorize your models and apply filters when listing models in your workspace."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Model\n",
|
|
||||||
"\n",
|
|
||||||
"model = Model.register(workspace=ws,\n",
|
|
||||||
" model_name='sklearn_regression_model.pkl', # Name of the registered model in your workspace.\n",
|
|
||||||
" model_path='./sklearn_regression_model.pkl', # Local file to upload and register as a model.\n",
|
|
||||||
" model_framework=Model.Framework.SCIKITLEARN, # Framework used to create the model.\n",
|
|
||||||
" model_framework_version='0.19.1', # Version of scikit-learn used to create the model.\n",
|
|
||||||
" description='Ridge regression model to predict diabetes progression.',\n",
|
|
||||||
" tags={'area': 'diabetes', 'type': 'regression'})\n",
|
|
||||||
"\n",
|
|
||||||
"print('Name:', model.name)\n",
|
|
||||||
"print('Version:', model.version)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Register an environment (for all models)\n",
|
|
||||||
"\n",
|
|
||||||
"If you control over how your model is run, or if it has special runtime requirements, you can specify your own environment and scoring method.\n",
|
|
||||||
"\n",
|
|
||||||
"Specify the model's runtime environment by creating an [Environment](https://docs.microsoft.com/python/api/azureml-core/azureml.core.environment%28class%29?view=azure-ml-py) object and providing the [CondaDependencies](https://docs.microsoft.com/python/api/azureml-core/azureml.core.conda_dependencies.condadependencies?view=azure-ml-py) needed by your model."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Environment\n",
|
|
||||||
"from azureml.core.conda_dependencies import CondaDependencies\n",
|
|
||||||
"\n",
|
|
||||||
"environment=Environment('my-sklearn-environment')\n",
|
|
||||||
"environment.python.conda_dependencies = CondaDependencies.create(conda_packages=[\n",
|
|
||||||
" 'pip==20.2.4'],\n",
|
|
||||||
" pip_packages=[\n",
|
|
||||||
" 'azureml-defaults',\n",
|
|
||||||
" 'inference-schema[numpy-support]',\n",
|
|
||||||
" 'numpy==1.23',\n",
|
|
||||||
" 'scikit-learn==0.22.1',\n",
|
|
||||||
" 'scipy'\n",
|
|
||||||
"])"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"When using a custom environment, you must also provide Python code for initializing and running your model. An example script is included with this notebook."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"with open('score.py') as f:\n",
|
|
||||||
" print(f.read())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Create the InferenceConfig\n",
|
|
||||||
"Create the inference configuration to reference your environment and entry script during deployment"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import InferenceConfig\n",
|
|
||||||
"\n",
|
|
||||||
"inference_config = InferenceConfig(entry_script='score.py', \n",
|
|
||||||
" source_directory='.',\n",
|
|
||||||
" environment=environment)\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Provision the AKS Cluster\n",
|
|
||||||
"If you already have an AKS cluster attached to this workspace, skip the step below and provide the name of the cluster.\n",
|
|
||||||
"\n",
|
|
||||||
"> Note that if you have an AzureML Data Scientist role, you will not have permission to create compute resources. Talk to your workspace or IT admin to create the compute targets described in this section, if they do not already exist."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.compute import AksCompute\n",
|
|
||||||
"from azureml.core.compute import ComputeTarget\n",
|
|
||||||
"# Use the default configuration (can also provide parameters to customize)\n",
|
|
||||||
"prov_config = AksCompute.provisioning_configuration()\n",
|
|
||||||
"\n",
|
|
||||||
"aks_name = 'my-aks' \n",
|
|
||||||
"# Create the cluster\n",
|
|
||||||
"aks_target = ComputeTarget.create(workspace = ws, \n",
|
|
||||||
" name = aks_name, \n",
|
|
||||||
" provisioning_configuration = prov_config) \n",
|
|
||||||
"aks_target.wait_for_completion(show_output=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Create an Endpoint and add a version (AKS service)\n",
|
|
||||||
"This creates a new endpoint and adds a version behind it. By default the first version added is the default version. You can specify the traffic percentile a version takes behind an endpoint. \n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# deploying the model and create a new endpoint\n",
|
|
||||||
"from azureml.core.webservice import AksEndpoint\n",
|
|
||||||
"# from azureml.core.compute import ComputeTarget\n",
|
|
||||||
"\n",
|
|
||||||
"#select a created compute\n",
|
|
||||||
"compute = ComputeTarget(ws, 'my-aks')\n",
|
|
||||||
"namespace_name=\"endpointnamespace\"\n",
|
|
||||||
"# define the endpoint name\n",
|
|
||||||
"endpoint_name = \"myendpoint1\"\n",
|
|
||||||
"# define the service name\n",
|
|
||||||
"version_name= \"versiona\"\n",
|
|
||||||
"\n",
|
|
||||||
"endpoint_deployment_config = AksEndpoint.deploy_configuration(tags = {'modelVersion':'firstversion', 'department':'finance'}, \n",
|
|
||||||
" description = \"my first version\", namespace = namespace_name, \n",
|
|
||||||
" version_name = version_name, traffic_percentile = 40)\n",
|
|
||||||
"\n",
|
|
||||||
"endpoint = Model.deploy(ws, endpoint_name, [model], inference_config, endpoint_deployment_config, compute)\n",
|
|
||||||
"endpoint.wait_for_deployment(True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"endpoint.get_logs()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Add another version of the service to an existing endpoint\n",
|
|
||||||
"This adds another version behind an existing endpoint. You can specify the traffic percentile the new version takes. If no traffic_percentile is specified then it defaults to 0. All the unspecified traffic percentile (in this example 50) across all versions goes to default version."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Adding a new version to an existing Endpoint.\n",
|
|
||||||
"version_name_add=\"versionb\" \n",
|
|
||||||
"\n",
|
|
||||||
"endpoint.create_version(version_name = version_name_add, inference_config=inference_config, models=[model], tags = {'modelVersion':'secondversion', 'department':'finance'}, \n",
|
|
||||||
" description = \"my second version\", traffic_percentile = 10)\n",
|
|
||||||
"endpoint.wait_for_deployment(True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Update an existing version in an endpoint\n",
|
|
||||||
"There are two types of versions: control and treatment. An endpoint contains one or more treatment versions but only one control version. This categorization helps compare the different versions against the defined control version."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"endpoint.update_version(version_name=endpoint.versions[version_name_add].name, description=\"my second version update\", traffic_percentile=40, is_default=True, is_control_version_type=True)\n",
|
|
||||||
"endpoint.wait_for_deployment(True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Test the web service using run method\n",
|
|
||||||
"Test the web sevice by passing in data. Run() method retrieves API keys behind the scenes to make sure that call is authenticated."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Scoring on endpoint\n",
|
|
||||||
"import json\n",
|
|
||||||
"test_sample = json.dumps({'data': [\n",
|
|
||||||
" [1,2,3,4,5,6,7,8,9,10], \n",
|
|
||||||
" [10,9,8,7,6,5,4,3,2,1]\n",
|
|
||||||
"]})\n",
|
|
||||||
"\n",
|
|
||||||
"test_sample_encoded = bytes(test_sample, encoding='utf8')\n",
|
|
||||||
"prediction = endpoint.run(input_data=test_sample_encoded)\n",
|
|
||||||
"print(prediction)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Delete Resources"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# deleting a version in an endpoint\n",
|
|
||||||
"endpoint.delete_version(version_name=version_name)\n",
|
|
||||||
"endpoint.wait_for_deployment(True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# deleting an endpoint, this will delete all versions in the endpoint and the endpoint itself\n",
|
|
||||||
"endpoint.delete()"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "shipatel"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"category": "deployment",
|
|
||||||
"compute": [
|
|
||||||
"None"
|
|
||||||
],
|
|
||||||
"datasets": [
|
|
||||||
"Diabetes"
|
|
||||||
],
|
|
||||||
"deployment": [
|
|
||||||
"Azure Kubernetes Service"
|
|
||||||
],
|
|
||||||
"exclude_from_index": false,
|
|
||||||
"framework": [
|
|
||||||
"Scikit-learn"
|
|
||||||
],
|
|
||||||
"friendly_name": "Deploy models to AKS using controlled roll out",
|
|
||||||
"index_order": 3,
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3.8 - AzureML",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python38-azureml"
|
|
||||||
},
|
|
||||||
"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.6.0"
|
|
||||||
},
|
|
||||||
"star_tag": [
|
|
||||||
"featured"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"None"
|
|
||||||
],
|
|
||||||
"task": "Deploy a model with Azure Machine Learning"
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
name: deploy-aks-with-controlled-rollout
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import pickle
|
|
||||||
import json
|
|
||||||
import numpy
|
|
||||||
from sklearn.externals import joblib
|
|
||||||
from sklearn.linear_model import Ridge
|
|
||||||
from azureml.core.model import Model
|
|
||||||
|
|
||||||
|
|
||||||
def init():
|
|
||||||
global model
|
|
||||||
# note here "sklearn_regression_model.pkl" is the name of the model registered under
|
|
||||||
# this is a different behavior than before when the code is run locally, even though the code is the same.
|
|
||||||
model_path = Model.get_model_path('sklearn_regression_model.pkl')
|
|
||||||
# deserialize the model file back into a sklearn model
|
|
||||||
model = joblib.load(model_path)
|
|
||||||
|
|
||||||
|
|
||||||
# note you can pass in multiple rows for scoring
|
|
||||||
def run(raw_data):
|
|
||||||
try:
|
|
||||||
data = json.loads(raw_data)['data']
|
|
||||||
data = numpy.array(data)
|
|
||||||
result = model.predict(data)
|
|
||||||
# you can return any data type as long as it is JSON-serializable
|
|
||||||
return result.tolist()
|
|
||||||
except Exception as e:
|
|
||||||
error = str(e)
|
|
||||||
return error
|
|
||||||
Binary file not shown.
@@ -1,498 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Enabling App Insights for Services in Production\n",
|
|
||||||
"With this notebook, you can learn how to enable App Insights for standard service monitoring, plus, we provide examples for doing custom logging within a scoring files in a model.\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"## What does Application Insights monitor?\n",
|
|
||||||
"It monitors request rates, response times, failure rates, etc. For more information visit [App Insights docs.](https://docs.microsoft.com/en-us/azure/application-insights/app-insights-overview)\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"## What is different compared to standard production deployment process?\n",
|
|
||||||
"If you want to enable generic App Insights for a service run:\n",
|
|
||||||
"```python\n",
|
|
||||||
"aks_service= Webservice(ws, \"aks-w-dc2\")\n",
|
|
||||||
"aks_service.update(enable_app_insights=True)```\n",
|
|
||||||
"Where \"aks-w-dc2\" is your service name. You can also do this from the Azure Portal under your Workspace--> deployments--> Select deployment--> Edit--> Advanced Settings--> Select \"Enable AppInsights diagnostics\"\n",
|
|
||||||
"\n",
|
|
||||||
"If you want to log custom traces, you will follow the standard deplyment process for AKS and you will:\n",
|
|
||||||
"1. Update scoring file.\n",
|
|
||||||
"2. Update aks configuration.\n",
|
|
||||||
"3. Deploy the model with this new configuration. "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## 1. Import your dependencies"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import azureml.core\n",
|
|
||||||
"import json\n",
|
|
||||||
"\n",
|
|
||||||
"from azureml.core import Workspace\n",
|
|
||||||
"from azureml.core.compute import AksCompute, ComputeTarget\n",
|
|
||||||
"from azureml.core.webservice import AksWebservice\n",
|
|
||||||
"\n",
|
|
||||||
"print(azureml.core.VERSION)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## 2. Set up your configuration and create a workspace\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"ws = Workspace.from_config()\n",
|
|
||||||
"print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep='\\n')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## 3. Register Model\n",
|
|
||||||
"Register an existing trained model, add descirption and tags."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Model\n",
|
|
||||||
"\n",
|
|
||||||
"model = Model.register(model_path=\"sklearn_regression_model.pkl\", # This points to a local file.\n",
|
|
||||||
" model_name=\"sklearn_regression_model.pkl\", # This is the name the model is registered as.\n",
|
|
||||||
" tags={'area': \"diabetes\", 'type': \"regression\"},\n",
|
|
||||||
" description=\"Ridge regression model to predict diabetes\",\n",
|
|
||||||
" workspace=ws)\n",
|
|
||||||
"\n",
|
|
||||||
"print(model.name, model.description, model.version)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## 4. *Update your scoring file with custom print statements*\n",
|
|
||||||
"Here is an example:\n",
|
|
||||||
"### a. In your init function add:\n",
|
|
||||||
"```python\n",
|
|
||||||
"print (\"model initialized\" + time.strftime(\"%H:%M:%S\"))```\n",
|
|
||||||
"\n",
|
|
||||||
"### b. In your run function add:\n",
|
|
||||||
"```python\n",
|
|
||||||
"print (\"Prediction created\" + time.strftime(\"%H:%M:%S\"))```"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%writefile score.py\n",
|
|
||||||
"import os\n",
|
|
||||||
"import pickle\n",
|
|
||||||
"import json\n",
|
|
||||||
"import numpy\n",
|
|
||||||
"from sklearn.externals import joblib\n",
|
|
||||||
"from sklearn.linear_model import Ridge\n",
|
|
||||||
"import time\n",
|
|
||||||
"\n",
|
|
||||||
"def init():\n",
|
|
||||||
" global model\n",
|
|
||||||
" #Print statement for appinsights custom traces:\n",
|
|
||||||
" print (\"model initialized\" + time.strftime(\"%H:%M:%S\"))\n",
|
|
||||||
"\n",
|
|
||||||
" # AZUREML_MODEL_DIR is an environment variable created during deployment.\n",
|
|
||||||
" # It is the path to the model folder (./azureml-models/$MODEL_NAME/$VERSION)\n",
|
|
||||||
" # For multiple models, it points to the folder containing all deployed models (./azureml-models)\n",
|
|
||||||
" model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'sklearn_regression_model.pkl')\n",
|
|
||||||
"\n",
|
|
||||||
" # deserialize the model file back into a sklearn model\n",
|
|
||||||
" model = joblib.load(model_path)\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"# note you can pass in multiple rows for scoring\n",
|
|
||||||
"def run(raw_data):\n",
|
|
||||||
" try:\n",
|
|
||||||
" data = json.loads(raw_data)['data']\n",
|
|
||||||
" data = numpy.array(data)\n",
|
|
||||||
" result = model.predict(data)\n",
|
|
||||||
" print (\"Prediction created\" + time.strftime(\"%H:%M:%S\"))\n",
|
|
||||||
" # you can return any datatype as long as it is JSON-serializable\n",
|
|
||||||
" return result.tolist()\n",
|
|
||||||
" except Exception as e:\n",
|
|
||||||
" error = str(e)\n",
|
|
||||||
" print (error + time.strftime(\"%H:%M:%S\"))\n",
|
|
||||||
" return error"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## 5. *Create myenv.yml file*\n",
|
|
||||||
"Please note that you must indicate azureml-defaults with verion >= 1.0.45 as a pip dependency, because it contains the functionality needed to host the model as a web service."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.conda_dependencies import CondaDependencies\n",
|
|
||||||
"\n",
|
|
||||||
"myenv = CondaDependencies.create(conda_packages=['numpy==1.19.5','scikit-learn==0.22.1'],\n",
|
|
||||||
" pip_packages=['azureml-defaults'])\n",
|
|
||||||
"\n",
|
|
||||||
"with open(\"myenv.yml\",\"w\") as f:\n",
|
|
||||||
" f.write(myenv.serialize_to_string())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## 6. Create Inference Configuration"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.environment import Environment\n",
|
|
||||||
"from azureml.core.model import InferenceConfig\n",
|
|
||||||
"\n",
|
|
||||||
"myenv = Environment.from_conda_specification(name=\"myenv\", file_path=\"myenv.yml\")\n",
|
|
||||||
"inference_config = InferenceConfig(entry_script=\"score.py\", environment=myenv)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Deploy to ACI (Optional)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.webservice import AciWebservice\n",
|
|
||||||
"\n",
|
|
||||||
"aci_deployment_config = AciWebservice.deploy_configuration(cpu_cores=1,\n",
|
|
||||||
" memory_gb=1,\n",
|
|
||||||
" tags={'area': \"diabetes\", 'type': \"regression\"},\n",
|
|
||||||
" description=\"Predict diabetes using regression model\",\n",
|
|
||||||
" enable_app_insights=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"aci_service_name = \"aci-service-appinsights\"\n",
|
|
||||||
"\n",
|
|
||||||
"aci_service = Model.deploy(ws, aci_service_name, [model], inference_config, aci_deployment_config, overwrite=True)\n",
|
|
||||||
"aci_service.wait_for_deployment(show_output=True)\n",
|
|
||||||
"\n",
|
|
||||||
"print(aci_service.state)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"if aci_service.state == \"Healthy\":\n",
|
|
||||||
" test_sample = json.dumps({\n",
|
|
||||||
" \"data\": [\n",
|
|
||||||
" [1,28,13,45,54,6,57,8,8,10],\n",
|
|
||||||
" [101,9,8,37,6,45,4,3,2,41]\n",
|
|
||||||
" ]\n",
|
|
||||||
" })\n",
|
|
||||||
"\n",
|
|
||||||
" prediction = aci_service.run(test_sample)\n",
|
|
||||||
"\n",
|
|
||||||
" print(prediction)\n",
|
|
||||||
"else:\n",
|
|
||||||
" raise ValueError(\"Service deployment isn't healthy, can't call the service. Error: \", aci_service.error)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## 7. Deploy to AKS service"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Create AKS compute if you haven't done so.\n",
|
|
||||||
"\n",
|
|
||||||
"> Note that if you have an AzureML Data Scientist role, you will not have permission to create compute resources. Talk to your workspace or IT admin to create the compute targets described in this section, if they do not already exist."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.compute import ComputeTarget, AksCompute\n",
|
|
||||||
"from azureml.core.compute_target import ComputeTargetException\n",
|
|
||||||
"\n",
|
|
||||||
"aks_name = \"my-aks-insights\"\n",
|
|
||||||
"\n",
|
|
||||||
"creating_compute = False\n",
|
|
||||||
"try:\n",
|
|
||||||
" aks_target = ComputeTarget(ws, aks_name)\n",
|
|
||||||
" print(\"Using existing AKS compute target {}.\".format(aks_name))\n",
|
|
||||||
"except ComputeTargetException:\n",
|
|
||||||
" print(\"Creating a new AKS compute target {}.\".format(aks_name))\n",
|
|
||||||
"\n",
|
|
||||||
" # Use the default configuration (can also provide parameters to customize).\n",
|
|
||||||
" prov_config = AksCompute.provisioning_configuration()\n",
|
|
||||||
" aks_target = ComputeTarget.create(workspace=ws,\n",
|
|
||||||
" name=aks_name,\n",
|
|
||||||
" provisioning_configuration=prov_config)\n",
|
|
||||||
" creating_compute = True"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%time\n",
|
|
||||||
"if creating_compute and aks_target.provisioning_state != \"Succeeded\":\n",
|
|
||||||
" aks_target.wait_for_completion(show_output=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"print(aks_target.provisioning_state)\n",
|
|
||||||
"print(aks_target.provisioning_errors)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"If you already have a cluster you can attach the service to it:"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"```python\n",
|
|
||||||
"%%time\n",
|
|
||||||
"resource_id = '/subscriptions/<subscriptionid>/resourcegroups/<resourcegroupname>/providers/Microsoft.ContainerService/managedClusters/<aksservername>'\n",
|
|
||||||
"create_name= 'myaks4'\n",
|
|
||||||
"attach_config = AksCompute.attach_configuration(resource_id=resource_id)\n",
|
|
||||||
"aks_target = ComputeTarget.attach(workspace=ws,\n",
|
|
||||||
" name=create_name,\n",
|
|
||||||
" attach_configuration=attach_config)\n",
|
|
||||||
"## Wait for the operation to complete\n",
|
|
||||||
"aks_target.wait_for_provisioning(True)```"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### a. *Activate App Insights through updating AKS Webservice configuration*\n",
|
|
||||||
"In order to enable App Insights in your service you will need to update your AKS configuration file:"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Set the web service configuration.\n",
|
|
||||||
"aks_deployment_config = AksWebservice.deploy_configuration(enable_app_insights=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### b. Deploy your service"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"if aks_target.provisioning_state == \"Succeeded\":\n",
|
|
||||||
" aks_service_name = \"aks-service-appinsights\"\n",
|
|
||||||
" aks_service = Model.deploy(ws,\n",
|
|
||||||
" aks_service_name,\n",
|
|
||||||
" [model],\n",
|
|
||||||
" inference_config,\n",
|
|
||||||
" aks_deployment_config,\n",
|
|
||||||
" deployment_target=aks_target,\n",
|
|
||||||
" overwrite=True)\n",
|
|
||||||
" aks_service.wait_for_deployment(show_output=True)\n",
|
|
||||||
" print(aks_service.state)\n",
|
|
||||||
"else:\n",
|
|
||||||
" raise ValueError(\"AKS cluster provisioning failed. Error: \", aks_target.provisioning_errors)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## 8. Test your service "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%time\n",
|
|
||||||
"\n",
|
|
||||||
"if aks_service.state == \"Healthy\":\n",
|
|
||||||
" test_sample = json.dumps({\n",
|
|
||||||
" \"data\": [\n",
|
|
||||||
" [1,28,13,45,54,6,57,8,8,10],\n",
|
|
||||||
" [101,9,8,37,6,45,4,3,2,41]\n",
|
|
||||||
" ]\n",
|
|
||||||
" })\n",
|
|
||||||
"\n",
|
|
||||||
" prediction = aks_service.run(input_data=test_sample)\n",
|
|
||||||
" print(prediction)\n",
|
|
||||||
"else:\n",
|
|
||||||
" raise ValueError(\"Service deployment isn't healthy, can't call the service. Error: \", aks_service.error)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## 9. See your service telemetry in App Insights\n",
|
|
||||||
"1. Go to the [Azure Portal](https://portal.azure.com/)\n",
|
|
||||||
"2. All resources--> Select the subscription/resource group where you created your Workspace--> Select the App Insights type\n",
|
|
||||||
"3. Click on the AppInsights resource. You'll see a highlevel dashboard with information on Requests, Server response time and availability.\n",
|
|
||||||
"4. Click on the top banner \"Analytics\"\n",
|
|
||||||
"5. In the \"Schema\" section select \"traces\" and run your query.\n",
|
|
||||||
"6. Voila! All your custom traces should be there."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Disable App Insights"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"aks_service.update(enable_app_insights=False)\n",
|
|
||||||
"aks_service.wait_for_deployment(show_output=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Clean up"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%time\n",
|
|
||||||
"aks_service.delete()\n",
|
|
||||||
"aci_service.delete()\n",
|
|
||||||
"model.delete()\n",
|
|
||||||
"if creating_compute:\n",
|
|
||||||
" aks_target.delete()"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "gopalv"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3.8 - AzureML",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python38-azureml"
|
|
||||||
},
|
|
||||||
"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.6.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
name: enable-app-insights-in-production-service
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
Binary file not shown.
@@ -1,2 +0,0 @@
|
|||||||
RUN apt-get update
|
|
||||||
RUN apt-get install -y libgomp1
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
# ONNX on Azure Machine Learning
|
|
||||||
|
|
||||||
These tutorials show how to create and deploy Open Neural Network eXchange ([ONNX](http://onnx.ai)) models in Azure Machine Learning environments using [ONNX Runtime](https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-build-deploy-onnx) for inference. Once deployed as a web service, you can ping the model with your own set of images to be analyzed!
|
|
||||||
|
|
||||||
## Tutorials
|
|
||||||
|
|
||||||
0. If you are using an Azure Machine Learning Notebook VM, you are all set. Otherwise, [Configure your Azure Machine Learning Workspace](../../../configuration.ipynb)
|
|
||||||
|
|
||||||
#### Obtain pretrained models from the [ONNX Model Zoo](https://github.com/onnx/models) and deploy with ONNX Runtime
|
|
||||||
1. [MNIST - Handwritten Digit Classification with ONNX Runtime](onnx-inference-mnist-deploy.ipynb)
|
|
||||||
2. [Emotion FER+ - Facial Expression Recognition with ONNX Runtime](onnx-inference-facial-expression-recognition-deploy.ipynb)
|
|
||||||
|
|
||||||
#### Train model on Azure ML, convert to ONNX, and deploy with ONNX Runtime
|
|
||||||
3. [MNIST - Train using PyTorch and deploy with ONNX Runtime](onnx-train-pytorch-aml-deploy-mnist.ipynb)
|
|
||||||
|
|
||||||
#### Demo Notebooks from Microsoft Ignite 2018
|
|
||||||
Note that the following notebooks do not have evaluation sections for the models since they were deployed as part of a live demo. You can find the respective pre-processing and post-processing code linked from the ONNX Model Zoo Github pages ([ResNet](https://github.com/onnx/models/tree/master/models/image_classification/resnet), [TinyYoloV2](https://github.com/onnx/models/tree/master/tiny_yolov2)), or experiment with the ONNX models by [running them in the browser](https://microsoft.github.io/onnxjs-demo/#/).
|
|
||||||
|
|
||||||
4. [ResNet50 - Image Recognition with ONNX Runtime](onnx-modelzoo-aml-deploy-resnet50.ipynb)
|
|
||||||
5. [TinyYoloV2 - Convert from CoreML and deploy with ONNX Runtime](onnx-convert-aml-deploy-tinyyolo.ipynb)
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
- [ONNX Runtime Python API Documentation](http://aka.ms/onnxruntime-python)
|
|
||||||
- [Azure Machine Learning API Documentation](http://aka.ms/aml-docs)
|
|
||||||
|
|
||||||
## Related Articles
|
|
||||||
- [Building and Deploying ONNX Runtime Models](https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-build-deploy-onnx)
|
|
||||||
- [Azure AI – Making AI Real for Business](https://aka.ms/aml-blog-overview)
|
|
||||||
- [What’s new in Azure Machine Learning](https://aka.ms/aml-blog-whats-new)
|
|
||||||
|
|
||||||
## License
|
|
||||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
Licensed under the MIT License.
|
|
||||||
|
|
||||||
## Acknowledgements
|
|
||||||
These tutorials were developed by Vinitra Swamy and Prasanth Pulavarthi of the Microsoft AI Frameworks team and adapted for presentation at Microsoft Ignite 2018.
|
|
||||||
|
|
||||||
|
|
||||||

|
|
||||||
Binary file not shown.
@@ -1,135 +0,0 @@
|
|||||||
# This is a modified version of https://github.com/pytorch/examples/blob/master/mnist/main.py which is
|
|
||||||
# licensed under BSD 3-Clause (https://github.com/pytorch/examples/blob/master/LICENSE)
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
import argparse
|
|
||||||
import torch
|
|
||||||
import torch.nn as nn
|
|
||||||
import torch.nn.functional as F
|
|
||||||
import torch.optim as optim
|
|
||||||
from torchvision import datasets, transforms
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
class Net(nn.Module):
|
|
||||||
def __init__(self):
|
|
||||||
super(Net, self).__init__()
|
|
||||||
self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
|
|
||||||
self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
|
|
||||||
self.conv2_drop = nn.Dropout2d()
|
|
||||||
self.fc1 = nn.Linear(320, 50)
|
|
||||||
self.fc2 = nn.Linear(50, 10)
|
|
||||||
|
|
||||||
def forward(self, x):
|
|
||||||
x = F.relu(F.max_pool2d(self.conv1(x), 2))
|
|
||||||
x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
|
|
||||||
x = x.view(-1, 320)
|
|
||||||
x = F.relu(self.fc1(x))
|
|
||||||
x = F.dropout(x, training=self.training)
|
|
||||||
x = self.fc2(x)
|
|
||||||
return F.log_softmax(x, dim=1)
|
|
||||||
|
|
||||||
|
|
||||||
def train(args, model, device, train_loader, optimizer, epoch, output_dir):
|
|
||||||
model.train()
|
|
||||||
for batch_idx, (data, target) in enumerate(train_loader):
|
|
||||||
data, target = data.to(device), target.to(device)
|
|
||||||
optimizer.zero_grad()
|
|
||||||
output = model(data)
|
|
||||||
loss = F.nll_loss(output, target)
|
|
||||||
loss.backward()
|
|
||||||
optimizer.step()
|
|
||||||
if batch_idx % args.log_interval == 0:
|
|
||||||
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
|
|
||||||
epoch, batch_idx * len(data), len(train_loader.dataset),
|
|
||||||
100. * batch_idx / len(train_loader), loss.item()))
|
|
||||||
|
|
||||||
|
|
||||||
def test(args, model, device, test_loader):
|
|
||||||
model.eval()
|
|
||||||
test_loss = 0
|
|
||||||
correct = 0
|
|
||||||
with torch.no_grad():
|
|
||||||
for data, target in test_loader:
|
|
||||||
data, target = data.to(device), target.to(device)
|
|
||||||
output = model(data)
|
|
||||||
test_loss += F.nll_loss(output, target, size_average=False, reduce=True).item() # sum up batch loss
|
|
||||||
pred = output.max(1, keepdim=True)[1] # get the index of the max log-probability
|
|
||||||
correct += pred.eq(target.view_as(pred)).sum().item()
|
|
||||||
|
|
||||||
test_loss /= len(test_loader.dataset)
|
|
||||||
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
|
|
||||||
test_loss, correct, len(test_loader.dataset),
|
|
||||||
100. * correct / len(test_loader.dataset)))
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
# Training settings
|
|
||||||
parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
|
|
||||||
parser.add_argument('--batch-size', type=int, default=64, metavar='N',
|
|
||||||
help='input batch size for training (default: 64)')
|
|
||||||
parser.add_argument('--test-batch-size', type=int, default=1000, metavar='N',
|
|
||||||
help='input batch size for testing (default: 1000)')
|
|
||||||
parser.add_argument('--epochs', type=int, default=5, metavar='N',
|
|
||||||
help='number of epochs to train (default: 5)')
|
|
||||||
parser.add_argument('--lr', type=float, default=0.01, metavar='LR',
|
|
||||||
help='learning rate (default: 0.01)')
|
|
||||||
parser.add_argument('--momentum', type=float, default=0.5, metavar='M',
|
|
||||||
help='SGD momentum (default: 0.5)')
|
|
||||||
parser.add_argument('--no-cuda', action='store_true', default=False,
|
|
||||||
help='disables CUDA training')
|
|
||||||
parser.add_argument('--seed', type=int, default=1, metavar='S',
|
|
||||||
help='random seed (default: 1)')
|
|
||||||
parser.add_argument('--log-interval', type=int, default=10, metavar='N',
|
|
||||||
help='how many batches to wait before logging training status')
|
|
||||||
parser.add_argument('--output-dir', type=str, default='outputs')
|
|
||||||
args = parser.parse_args()
|
|
||||||
use_cuda = not args.no_cuda and torch.cuda.is_available()
|
|
||||||
|
|
||||||
torch.manual_seed(args.seed)
|
|
||||||
|
|
||||||
device = torch.device("cuda" if use_cuda else "cpu")
|
|
||||||
|
|
||||||
output_dir = args.output_dir
|
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
|
||||||
|
|
||||||
kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}
|
|
||||||
# Use Azure Open Datasets for MNIST dataset
|
|
||||||
datasets.MNIST.resources = [
|
|
||||||
("https://azureopendatastorage.azurefd.net/mnist/train-images-idx3-ubyte.gz",
|
|
||||||
"f68b3c2dcbeaaa9fbdd348bbdeb94873"),
|
|
||||||
("https://azureopendatastorage.azurefd.net/mnist/train-labels-idx1-ubyte.gz",
|
|
||||||
"d53e105ee54ea40749a09fcbcd1e9432"),
|
|
||||||
("https://azureopendatastorage.azurefd.net/mnist/t10k-images-idx3-ubyte.gz",
|
|
||||||
"9fb629c4189551a2d022fa330f9573f3"),
|
|
||||||
("https://azureopendatastorage.azurefd.net/mnist/t10k-labels-idx1-ubyte.gz",
|
|
||||||
"ec29112dd5afa0611ce80d1b7f02629c")
|
|
||||||
]
|
|
||||||
train_loader = torch.utils.data.DataLoader(
|
|
||||||
datasets.MNIST('data', train=True, download=True,
|
|
||||||
transform=transforms.Compose([transforms.ToTensor(),
|
|
||||||
transforms.Normalize((0.1307,), (0.3081,))])
|
|
||||||
),
|
|
||||||
batch_size=args.batch_size, shuffle=True, **kwargs)
|
|
||||||
test_loader = torch.utils.data.DataLoader(
|
|
||||||
datasets.MNIST('data', train=False,
|
|
||||||
transform=transforms.Compose([transforms.ToTensor(),
|
|
||||||
transforms.Normalize((0.1307,), (0.3081,))])
|
|
||||||
),
|
|
||||||
batch_size=args.test_batch_size, shuffle=True, **kwargs)
|
|
||||||
|
|
||||||
model = Net().to(device)
|
|
||||||
optimizer = optim.SGD(model.parameters(), lr=args.lr, momentum=args.momentum)
|
|
||||||
|
|
||||||
for epoch in range(1, args.epochs + 1):
|
|
||||||
train(args, model, device, train_loader, optimizer, epoch, output_dir)
|
|
||||||
test(args, model, device, test_loader)
|
|
||||||
|
|
||||||
# save model
|
|
||||||
dummy_input = torch.randn(1, 1, 28, 28, device=device)
|
|
||||||
model_path = os.path.join(output_dir, 'mnist.onnx')
|
|
||||||
torch.onnx.export(model, dummy_input, model_path)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
@@ -1,434 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Copyright (c) Microsoft Corporation. All rights reserved. \n",
|
|
||||||
"\n",
|
|
||||||
"Licensed under the MIT License."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# YOLO Real-time Object Detection using ONNX on AzureML\n",
|
|
||||||
"\n",
|
|
||||||
"This example shows how to convert the TinyYOLO model from CoreML to ONNX and operationalize it as a web service using Azure Machine Learning services and the ONNX Runtime.\n",
|
|
||||||
"\n",
|
|
||||||
"## What is ONNX\n",
|
|
||||||
"ONNX is an open format for representing machine learning and deep learning models. ONNX enables open and interoperable AI by enabling data scientists and developers to use the tools of their choice without worrying about lock-in and flexibility to deploy to a variety of platforms. ONNX is developed and supported by a community of partners including Microsoft, Facebook, and Amazon. For more information, explore the [ONNX website](http://onnx.ai).\n",
|
|
||||||
"\n",
|
|
||||||
"## YOLO Details\n",
|
|
||||||
"You Only Look Once (YOLO) is a state-of-the-art, real-time object detection system. For more information about YOLO, please visit the [YOLO website](https://pjreddie.com/darknet/yolo/)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Prerequisites\n",
|
|
||||||
"\n",
|
|
||||||
"To make the best use of your time, make sure you have done the following:\n",
|
|
||||||
"\n",
|
|
||||||
"* Understand the [architecture and terms](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture) introduced by Azure Machine Learning\n",
|
|
||||||
"* If you are using an Azure Machine Learning Notebook VM, you are all set. Otherwise, go through the [configuration](../../../configuration.ipynb) notebook to:\n",
|
|
||||||
" * install the AML SDK\n",
|
|
||||||
" * create a workspace and its configuration file (config.json)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Check core SDK version number\n",
|
|
||||||
"import azureml.core\n",
|
|
||||||
"\n",
|
|
||||||
"print(\"SDK version:\", azureml.core.VERSION)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Install necessary packages\n",
|
|
||||||
"\n",
|
|
||||||
"You'll need to run the following commands to use this tutorial:\n",
|
|
||||||
"\n",
|
|
||||||
"```sh\n",
|
|
||||||
"pip install onnxmltools\n",
|
|
||||||
"pip install coremltools # use this on Linux and Mac\n",
|
|
||||||
"pip install git+https://github.com/apple/coremltools # use this on Windows\n",
|
|
||||||
"```"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Convert model to ONNX\n",
|
|
||||||
"\n",
|
|
||||||
"First we download the CoreML model. We use the CoreML model from [Matthijs Hollemans's tutorial](https://github.com/hollance/YOLO-CoreML-MPSNNGraph). This may take a few minutes."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import urllib.request\n",
|
|
||||||
"\n",
|
|
||||||
"coreml_model_url = \"https://github.com/hollance/YOLO-CoreML-MPSNNGraph/raw/master/TinyYOLO-CoreML/TinyYOLO-CoreML/TinyYOLO.mlmodel\"\n",
|
|
||||||
"urllib.request.urlretrieve(coreml_model_url, filename=\"TinyYOLO.mlmodel\")\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Then we use ONNXMLTools to convert the model."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import onnxmltools\n",
|
|
||||||
"import coremltools\n",
|
|
||||||
"\n",
|
|
||||||
"# Load a CoreML model\n",
|
|
||||||
"coreml_model = coremltools.utils.load_spec('TinyYOLO.mlmodel')\n",
|
|
||||||
"\n",
|
|
||||||
"# Convert from CoreML into ONNX\n",
|
|
||||||
"onnx_model = onnxmltools.convert_coreml(coreml_model, 'TinyYOLOv2')\n",
|
|
||||||
"\n",
|
|
||||||
"# Fix the preprocessor bias in the ImageScaler\n",
|
|
||||||
"for init in onnx_model.graph.initializer:\n",
|
|
||||||
" if init.name == 'scalerPreprocessor_bias':\n",
|
|
||||||
" init.dims[1] = 1\n",
|
|
||||||
"\n",
|
|
||||||
"# Save ONNX model\n",
|
|
||||||
"onnxmltools.utils.save_model(onnx_model, 'tinyyolov2.onnx')\n",
|
|
||||||
"\n",
|
|
||||||
"import os\n",
|
|
||||||
"print(os.path.getsize('tinyyolov2.onnx'))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Deploying as a web service with Azure ML\n",
|
|
||||||
"\n",
|
|
||||||
"### Load Azure ML workspace\n",
|
|
||||||
"\n",
|
|
||||||
"We begin by instantiating a workspace object from the existing workspace created earlier in the configuration notebook."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Workspace\n",
|
|
||||||
"\n",
|
|
||||||
"ws = Workspace.from_config()\n",
|
|
||||||
"print(ws.name, ws.location, ws.resource_group, sep = '\\n')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Registering your model with Azure ML\n",
|
|
||||||
"\n",
|
|
||||||
"Now we upload the model and register it in the workspace."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import Model\n",
|
|
||||||
"\n",
|
|
||||||
"model = Model.register(model_path = \"tinyyolov2.onnx\",\n",
|
|
||||||
" model_name = \"tinyyolov2\",\n",
|
|
||||||
" tags = {\"onnx\": \"demo\"},\n",
|
|
||||||
" description = \"TinyYOLO\",\n",
|
|
||||||
" workspace = ws)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Displaying your registered models\n",
|
|
||||||
"\n",
|
|
||||||
"You can optionally list out all the models that you have registered in this workspace."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"models = ws.models\n",
|
|
||||||
"for name, m in models.items():\n",
|
|
||||||
" print(\"Name:\", name,\"\\tVersion:\", m.version, \"\\tDescription:\", m.description, m.tags)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Write scoring file\n",
|
|
||||||
"\n",
|
|
||||||
"We are now going to deploy our ONNX model on Azure ML using the ONNX Runtime. We begin by writing a score.py file that will be invoked by the web service call. The `init()` function is called once when the container is started so we load the model using the ONNX Runtime into a global session object."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%writefile score.py\n",
|
|
||||||
"import json\n",
|
|
||||||
"import time\n",
|
|
||||||
"import sys\n",
|
|
||||||
"import os\n",
|
|
||||||
"from azureml.core.model import Model\n",
|
|
||||||
"import numpy as np # we're going to use numpy to process input and output data\n",
|
|
||||||
"import onnxruntime # to inference ONNX models, we use the ONNX Runtime\n",
|
|
||||||
"\n",
|
|
||||||
"def init():\n",
|
|
||||||
" global session\n",
|
|
||||||
" model = Model.get_model_path(model_name = 'tinyyolov2')\n",
|
|
||||||
" session = onnxruntime.InferenceSession(model)\n",
|
|
||||||
"\n",
|
|
||||||
"def preprocess(input_data_json):\n",
|
|
||||||
" # convert the JSON data into the tensor input\n",
|
|
||||||
" return np.array(json.loads(input_data_json)['data']).astype('float32')\n",
|
|
||||||
"\n",
|
|
||||||
"def postprocess(result):\n",
|
|
||||||
" return np.array(result).tolist()\n",
|
|
||||||
"\n",
|
|
||||||
"def run(input_data_json):\n",
|
|
||||||
" try:\n",
|
|
||||||
" start = time.time() # start timer\n",
|
|
||||||
" input_data = preprocess(input_data_json)\n",
|
|
||||||
" input_name = session.get_inputs()[0].name # get the id of the first input of the model \n",
|
|
||||||
" result = session.run([], {input_name: input_data})\n",
|
|
||||||
" end = time.time() # stop timer\n",
|
|
||||||
" return {\"result\": postprocess(result),\n",
|
|
||||||
" \"time\": end - start}\n",
|
|
||||||
" except Exception as e:\n",
|
|
||||||
" result = str(e)\n",
|
|
||||||
" return {\"error\": result}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Setting up inference configuration\n",
|
|
||||||
"First we create a YAML file that specifies which dependencies we would like to see in our container. Please note that you must include azureml-defaults with verion >= 1.0.45 as a pip dependency, because it contains the functionality needed to host the model as a web service."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.conda_dependencies import CondaDependencies \n",
|
|
||||||
"\n",
|
|
||||||
"myenv = CondaDependencies.create(pip_packages=[\"numpy\", \"onnxruntime\", \"azureml-core\", \"azureml-defaults\"])\n",
|
|
||||||
"\n",
|
|
||||||
"with open(\"myenv.yml\",\"w\") as f:\n",
|
|
||||||
" f.write(myenv.serialize_to_string())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Then we create the inference configuration."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import InferenceConfig\n",
|
|
||||||
"from azureml.core.environment import Environment\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"myenv = Environment.from_conda_specification(name=\"myenv\", file_path=\"myenv.yml\")\n",
|
|
||||||
"inference_config = InferenceConfig(entry_script=\"score.py\", environment=myenv)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Deploy the model"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.webservice import AciWebservice\n",
|
|
||||||
"\n",
|
|
||||||
"aciconfig = AciWebservice.deploy_configuration(cpu_cores = 1, \n",
|
|
||||||
" memory_gb = 1, \n",
|
|
||||||
" tags = {'demo': 'onnx'}, \n",
|
|
||||||
" description = 'web service for TinyYOLO ONNX model')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The following cell will take a few minutes to run as the model gets packaged up and deployed to ACI."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"aci_service_name = 'my-aci-service-tiny-yolo'\n",
|
|
||||||
"print(\"Service\", aci_service_name)\n",
|
|
||||||
"aci_service = Model.deploy(ws, aci_service_name, [model], inference_config, aciconfig)\n",
|
|
||||||
"aci_service.wait_for_deployment(True)\n",
|
|
||||||
"print(aci_service.state)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"In case the deployment fails, you can check the logs. Make sure to delete your aci_service before trying again."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"if aci_service.state != 'Healthy':\n",
|
|
||||||
" # run this command for debugging.\n",
|
|
||||||
" print(aci_service.get_logs())\n",
|
|
||||||
" aci_service.delete()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Success!\n",
|
|
||||||
"\n",
|
|
||||||
"If you've made it this far, you've deployed a working web service that does object detection using an ONNX model. You can get the URL for the webservice with the code below."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"print(aci_service.scoring_uri)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"When you are eventually done using the web service, remember to delete it."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"aci_service.delete()"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "viswamy"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"category": "deployment",
|
|
||||||
"compute": [
|
|
||||||
"local"
|
|
||||||
],
|
|
||||||
"datasets": [
|
|
||||||
"PASCAL VOC"
|
|
||||||
],
|
|
||||||
"deployment": [
|
|
||||||
"Azure Container Instance"
|
|
||||||
],
|
|
||||||
"exclude_from_index": false,
|
|
||||||
"framework": [
|
|
||||||
"ONNX"
|
|
||||||
],
|
|
||||||
"friendly_name": "Convert and deploy TinyYolo with ONNX Runtime",
|
|
||||||
"index_order": 5,
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3.8 - AzureML",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python38-azureml"
|
|
||||||
},
|
|
||||||
"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.6.5"
|
|
||||||
},
|
|
||||||
"star_tag": [
|
|
||||||
"featured"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"ONNX Converter"
|
|
||||||
],
|
|
||||||
"task": "Object Detection"
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
name: onnx-convert-aml-deploy-tinyyolo
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
- numpy
|
|
||||||
- git+https://github.com/apple/coremltools@v2.1
|
|
||||||
- onnx<1.7.0
|
|
||||||
- onnxmltools
|
|
||||||
@@ -1,801 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Copyright (c) Microsoft Corporation. All rights reserved. \n",
|
|
||||||
"Licensed under the MIT License."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Facial Expression Recognition (FER+) using ONNX Runtime on Azure ML\n",
|
|
||||||
"\n",
|
|
||||||
"This example shows how to deploy an image classification neural network using the Facial Expression Recognition ([FER](https://www.kaggle.com/c/challenges-in-representation-learning-facial-expression-recognition-challenge/data)) dataset and Open Neural Network eXchange format ([ONNX](http://aka.ms/onnxdocarticle)) on the Azure Machine Learning platform. This tutorial will show you how to deploy a FER+ model from the [ONNX model zoo](https://github.com/onnx/models), use it to make predictions using ONNX Runtime Inference, and deploy it as a web service in Azure.\n",
|
|
||||||
"\n",
|
|
||||||
"Throughout this tutorial, we will be referring to ONNX, a neural network exchange format used to represent deep learning models. With ONNX, AI developers can more easily move models between state-of-the-art tools (CNTK, PyTorch, Caffe, MXNet, TensorFlow) and choose the combination that is best for them. ONNX is developed and supported by a community of partners including Microsoft AI, Facebook, and Amazon. For more information, explore the [ONNX website](http://onnx.ai) and [open source files](https://github.com/onnx).\n",
|
|
||||||
"\n",
|
|
||||||
"[ONNX Runtime](https://aka.ms/onnxruntime-python) is the runtime engine that enables evaluation of trained machine learning (Traditional ML and Deep Learning) models with high performance and low resource utilization. We use the CPU version of ONNX Runtime in this tutorial, but will soon be releasing an additional tutorial for deploying this model using ONNX Runtime GPU.\n",
|
|
||||||
"\n",
|
|
||||||
"#### Tutorial Objectives:\n",
|
|
||||||
"\n",
|
|
||||||
"1. Describe the FER+ dataset and pretrained Convolutional Neural Net ONNX model for Emotion Recognition, stored in the ONNX model zoo.\n",
|
|
||||||
"2. Deploy and run the pretrained FER+ ONNX model on an Azure Machine Learning instance\n",
|
|
||||||
"3. Predict labels for test set data points in the cloud using ONNX Runtime and Azure ML"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Prerequisites\n",
|
|
||||||
"\n",
|
|
||||||
"### 1. Install Azure ML SDK and create a new workspace\n",
|
|
||||||
"If you are using an Azure Machine Learning Notebook VM, you are all set. Otherwise, please follow [Azure ML configuration notebook](../../../configuration.ipynb) to set up your environment.\n",
|
|
||||||
"\n",
|
|
||||||
"### 2. Install additional packages needed for this Notebook\n",
|
|
||||||
"You need to install the popular plotting library `matplotlib`, the image manipulation library `opencv`, and the `onnx` library in the conda environment where Azure Maching Learning SDK is installed.\n",
|
|
||||||
"\n",
|
|
||||||
"```sh\n",
|
|
||||||
"(myenv) $ pip install matplotlib onnx opencv-python\n",
|
|
||||||
"```\n",
|
|
||||||
"\n",
|
|
||||||
"**Debugging tip**: Make sure that to activate your virtual environment (myenv) before you re-launch this notebook using the `jupyter notebook` comand. Choose the respective Python kernel for your new virtual environment using the `Kernel > Change Kernel` menu above. If you have completed the steps correctly, the upper right corner of your screen should state `Python [conda env:myenv]` instead of `Python [default]`.\n",
|
|
||||||
"\n",
|
|
||||||
"### 3. Download sample data and pre-trained ONNX model from ONNX Model Zoo.\n",
|
|
||||||
"\n",
|
|
||||||
"In the following lines of code, we download [the trained ONNX Emotion FER+ model and corresponding test data](https://github.com/onnx/models/tree/master/vision/body_analysis/emotion_ferplus) and place them in the same folder as this tutorial notebook. For more information about the FER+ dataset, please visit Microsoft Researcher Emad Barsoum's [FER+ source data repository](https://github.com/ebarsoum/FERPlus)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# urllib is a built-in Python library to download files from URLs\n",
|
|
||||||
"\n",
|
|
||||||
"# Objective: retrieve the latest version of the ONNX Emotion FER+ model files from the\n",
|
|
||||||
"# ONNX Model Zoo and save it in the same folder as this tutorial\n",
|
|
||||||
"\n",
|
|
||||||
"import urllib.request\n",
|
|
||||||
"import os\n",
|
|
||||||
"\n",
|
|
||||||
"onnx_model_url = \"https://github.com/onnx/models/blob/main/vision/body_analysis/emotion_ferplus/model/emotion-ferplus-7.tar.gz?raw=true\"\n",
|
|
||||||
"\n",
|
|
||||||
"urllib.request.urlretrieve(onnx_model_url, filename=\"emotion-ferplus-7.tar.gz\")\n",
|
|
||||||
"os.mkdir(\"emotion_ferplus\")\n",
|
|
||||||
"\n",
|
|
||||||
"# the ! magic command tells our jupyter notebook kernel to run the following line of \n",
|
|
||||||
"# code from the command line instead of the notebook kernel\n",
|
|
||||||
"\n",
|
|
||||||
"# We use tar and xvcf to unzip the files we just retrieved from the ONNX model zoo\n",
|
|
||||||
"\n",
|
|
||||||
"!tar xvzf emotion-ferplus-7.tar.gz -C emotion_ferplus"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Deploy a VM with your ONNX model in the Cloud\n",
|
|
||||||
"\n",
|
|
||||||
"### Load Azure ML workspace\n",
|
|
||||||
"\n",
|
|
||||||
"We begin by instantiating a workspace object from the existing workspace created earlier in the configuration notebook."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Check core SDK version number\n",
|
|
||||||
"import azureml.core\n",
|
|
||||||
"\n",
|
|
||||||
"print(\"SDK version:\", azureml.core.VERSION)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Workspace\n",
|
|
||||||
"\n",
|
|
||||||
"ws = Workspace.from_config()\n",
|
|
||||||
"print(ws.name, ws.location, ws.resource_group, sep = '\\n')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Registering your model with Azure ML"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"model_dir = \"emotion_ferplus/model\" # replace this with the location of your model files\n",
|
|
||||||
"\n",
|
|
||||||
"# leave as is if it's in the same folder as this notebook"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import Model\n",
|
|
||||||
"\n",
|
|
||||||
"model = Model.register(model_path = model_dir + \"/\" + \"model.onnx\",\n",
|
|
||||||
" model_name = \"onnx_emotion\",\n",
|
|
||||||
" tags = {\"onnx\": \"demo\"},\n",
|
|
||||||
" description = \"FER+ emotion recognition CNN from ONNX Model Zoo\",\n",
|
|
||||||
" workspace = ws)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Optional: Displaying your registered models\n",
|
|
||||||
"\n",
|
|
||||||
"This step is not required, so feel free to skip it."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"models = ws.models\n",
|
|
||||||
"for name, m in models.items():\n",
|
|
||||||
" print(\"Name:\", name,\"\\tVersion:\", m.version, \"\\tDescription:\", m.description, m.tags)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### ONNX FER+ Model Methodology\n",
|
|
||||||
"\n",
|
|
||||||
"The image classification model we are using is pre-trained using Microsoft's deep learning cognitive toolkit, [CNTK](https://github.com/Microsoft/CNTK), from the [ONNX model zoo](http://github.com/onnx/models). The model zoo has many other models that can be deployed on cloud providers like AzureML without any additional training. To ensure that our cloud deployed model works, we use testing data from the well-known FER+ data set, provided as part of the [trained Emotion Recognition model](https://github.com/onnx/models/tree/master/vision/body_analysis/emotion_ferplus) in the ONNX model zoo.\n",
|
|
||||||
"\n",
|
|
||||||
"The original Facial Emotion Recognition (FER) Dataset was released in 2013 by Pierre-Luc Carrier and Aaron Courville as part of a [Kaggle Competition](https://www.kaggle.com/c/challenges-in-representation-learning-facial-expression-recognition-challenge/data), but some of the labels are not entirely appropriate for the expression. In the FER+ Dataset, each photo was evaluated by at least 10 croud sourced reviewers, creating a more accurate basis for ground truth. \n",
|
|
||||||
"\n",
|
|
||||||
"You can see the difference of label quality in the sample model input below. The FER labels are the first word below each image, and the FER+ labels are the second word below each image.\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"***Input: Photos of cropped faces from FER+ Dataset***\n",
|
|
||||||
"\n",
|
|
||||||
"***Task: Classify each facial image into its appropriate emotions in the emotion table***\n",
|
|
||||||
"\n",
|
|
||||||
"``` emotion_table = {'neutral':0, 'happiness':1, 'surprise':2, 'sadness':3, 'anger':4, 'disgust':5, 'fear':6, 'contempt':7} ```\n",
|
|
||||||
"\n",
|
|
||||||
"***Output: Emotion prediction for input image***\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"Remember, once the application is deployed in Azure ML, you can use your own images as input for the model to classify."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# for images and plots in this notebook\n",
|
|
||||||
"import matplotlib.pyplot as plt \n",
|
|
||||||
"\n",
|
|
||||||
"# display images inline\n",
|
|
||||||
"%matplotlib inline"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Model Description\n",
|
|
||||||
"\n",
|
|
||||||
"The FER+ model from the ONNX Model Zoo is summarized by the graphic below. You can see the entire workflow of our pre-trained model in the following image from Barsoum et. al's paper [\"Training Deep Networks for Facial Expression Recognition\n",
|
|
||||||
"with Crowd-Sourced Label Distribution\"](https://arxiv.org/pdf/1608.01041.pdf), with our (64 x 64) input images and our output probabilities for each of the labels."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Specify our Score and Environment Files"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"We are now going to deploy our ONNX Model on AML with inference in ONNX Runtime. We begin by writing a score.py file, which will help us run the model in our Azure ML virtual machine (VM), and then specify our environment by writing a yml file. You will also notice that we import the onnxruntime library to do runtime inference on our ONNX models (passing in input and evaluating out model's predicted output). More information on the API and commands can be found in the [ONNX Runtime documentation](https://aka.ms/onnxruntime).\n",
|
|
||||||
"\n",
|
|
||||||
"### Write Score File\n",
|
|
||||||
"\n",
|
|
||||||
"A score file is what tells our Azure cloud service what to do. After initializing our model using azureml.core.model, we start an ONNX Runtime inference session to evaluate the data passed in on our function calls."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%writefile score.py\n",
|
|
||||||
"import json\n",
|
|
||||||
"import numpy as np\n",
|
|
||||||
"import onnxruntime\n",
|
|
||||||
"import sys\n",
|
|
||||||
"import os\n",
|
|
||||||
"import time\n",
|
|
||||||
"\n",
|
|
||||||
"def init():\n",
|
|
||||||
" global session, input_name, output_name\n",
|
|
||||||
" model = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'model.onnx')\n",
|
|
||||||
" session = onnxruntime.InferenceSession(model, None)\n",
|
|
||||||
" input_name = session.get_inputs()[0].name\n",
|
|
||||||
" output_name = session.get_outputs()[0].name \n",
|
|
||||||
" \n",
|
|
||||||
"def run(input_data):\n",
|
|
||||||
" '''Purpose: evaluate test input in Azure Cloud using onnxruntime.\n",
|
|
||||||
" We will call the run function later from our Jupyter Notebook \n",
|
|
||||||
" so our azure service can evaluate our model input in the cloud. '''\n",
|
|
||||||
"\n",
|
|
||||||
" try:\n",
|
|
||||||
" # load in our data, convert to readable format\n",
|
|
||||||
" data = np.array(json.loads(input_data)['data']).astype('float32')\n",
|
|
||||||
" \n",
|
|
||||||
" start = time.time()\n",
|
|
||||||
" r = session.run([output_name], {input_name : data})\n",
|
|
||||||
" end = time.time()\n",
|
|
||||||
" \n",
|
|
||||||
" result = emotion_map(postprocess(r[0]))\n",
|
|
||||||
" \n",
|
|
||||||
" result_dict = {\"result\": result,\n",
|
|
||||||
" \"time_in_sec\": [end - start]}\n",
|
|
||||||
" except Exception as e:\n",
|
|
||||||
" result_dict = {\"error\": str(e)}\n",
|
|
||||||
" \n",
|
|
||||||
" return json.dumps(result_dict)\n",
|
|
||||||
"\n",
|
|
||||||
"def emotion_map(classes, N=1):\n",
|
|
||||||
" \"\"\"Take the most probable labels (output of postprocess) and returns the \n",
|
|
||||||
" top N emotional labels that fit the picture.\"\"\"\n",
|
|
||||||
" \n",
|
|
||||||
" emotion_table = {'neutral':0, 'happiness':1, 'surprise':2, 'sadness':3, \n",
|
|
||||||
" 'anger':4, 'disgust':5, 'fear':6, 'contempt':7}\n",
|
|
||||||
" \n",
|
|
||||||
" emotion_keys = list(emotion_table.keys())\n",
|
|
||||||
" emotions = []\n",
|
|
||||||
" for i in range(N):\n",
|
|
||||||
" emotions.append(emotion_keys[classes[i]])\n",
|
|
||||||
" return emotions\n",
|
|
||||||
"\n",
|
|
||||||
"def softmax(x):\n",
|
|
||||||
" \"\"\"Compute softmax values (probabilities from 0 to 1) for each possible label.\"\"\"\n",
|
|
||||||
" x = x.reshape(-1)\n",
|
|
||||||
" e_x = np.exp(x - np.max(x))\n",
|
|
||||||
" return e_x / e_x.sum(axis=0)\n",
|
|
||||||
"\n",
|
|
||||||
"def postprocess(scores):\n",
|
|
||||||
" \"\"\"This function takes the scores generated by the network and \n",
|
|
||||||
" returns the class IDs in decreasing order of probability.\"\"\"\n",
|
|
||||||
" prob = softmax(scores)\n",
|
|
||||||
" prob = np.squeeze(prob)\n",
|
|
||||||
" classes = np.argsort(prob)[::-1]\n",
|
|
||||||
" return classes"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Write Environment File\n",
|
|
||||||
"Please note that you must indicate azureml-defaults with verion >= 1.0.45 as a pip dependency, because it contains the functionality needed to host the model as a web service."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.conda_dependencies import CondaDependencies \n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"myenv = CondaDependencies.create(pip_packages=[\"numpy\", \"onnxruntime\", \"azureml-core\", \"azureml-defaults\"])\n",
|
|
||||||
"\n",
|
|
||||||
"with open(\"myenv.yml\",\"w\") as f:\n",
|
|
||||||
" f.write(myenv.serialize_to_string())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Setup inference configuration"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import InferenceConfig\n",
|
|
||||||
"from azureml.core.environment import Environment\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"myenv = Environment.from_conda_specification(name=\"myenv\", file_path=\"myenv.yml\")\n",
|
|
||||||
"inference_config = InferenceConfig(entry_script=\"score.py\", environment=myenv)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Deploy the model"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.webservice import AciWebservice\n",
|
|
||||||
"\n",
|
|
||||||
"aciconfig = AciWebservice.deploy_configuration(cpu_cores = 1, \n",
|
|
||||||
" memory_gb = 1, \n",
|
|
||||||
" tags = {'demo': 'onnx'}, \n",
|
|
||||||
" description = 'ONNX for emotion recognition model')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The following cell will likely take a few minutes to run as well."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"aci_service_name = 'onnx-demo-emotion'\n",
|
|
||||||
"print(\"Service\", aci_service_name)\n",
|
|
||||||
"aci_service = Model.deploy(ws, aci_service_name, [model], inference_config, aciconfig)\n",
|
|
||||||
"aci_service.wait_for_deployment(True)\n",
|
|
||||||
"print(aci_service.state)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"if aci_service.state != 'Healthy':\n",
|
|
||||||
" # run this command for debugging.\n",
|
|
||||||
" print(aci_service.get_logs())\n",
|
|
||||||
"\n",
|
|
||||||
" # If your deployment fails, make sure to delete your aci_service before trying again!\n",
|
|
||||||
" # aci_service.delete()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Success!\n",
|
|
||||||
"\n",
|
|
||||||
"If you've made it this far, you've deployed a working VM with a facial emotion recognition model running in the cloud using Azure ML. Congratulations!\n",
|
|
||||||
"\n",
|
|
||||||
"Let's see how well our model deals with our test images."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Testing and Evaluation\n",
|
|
||||||
"\n",
|
|
||||||
"### Useful Helper Functions\n",
|
|
||||||
"\n",
|
|
||||||
"We preprocess and postprocess our data (see score.py file) using the helper functions specified in the [ONNX FER+ Model page in the Model Zoo repository](https://github.com/onnx/models/tree/master/vision/body_analysis/emotion_ferplus)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"def emotion_map(classes, N=1):\n",
|
|
||||||
" \"\"\"Take the most probable labels (output of postprocess) and returns the \n",
|
|
||||||
" top N emotional labels that fit the picture.\"\"\"\n",
|
|
||||||
" \n",
|
|
||||||
" emotion_table = {'neutral':0, 'happiness':1, 'surprise':2, 'sadness':3, \n",
|
|
||||||
" 'anger':4, 'disgust':5, 'fear':6, 'contempt':7}\n",
|
|
||||||
" \n",
|
|
||||||
" emotion_keys = list(emotion_table.keys())\n",
|
|
||||||
" emotions = []\n",
|
|
||||||
" for c in range(N):\n",
|
|
||||||
" emotions.append(emotion_keys[classes[c]])\n",
|
|
||||||
" return emotions\n",
|
|
||||||
"\n",
|
|
||||||
"def softmax(x):\n",
|
|
||||||
" \"\"\"Compute softmax values (probabilities from 0 to 1) for each possible label.\"\"\"\n",
|
|
||||||
" x = x.reshape(-1)\n",
|
|
||||||
" e_x = np.exp(x - np.max(x))\n",
|
|
||||||
" return e_x / e_x.sum(axis=0)\n",
|
|
||||||
"\n",
|
|
||||||
"def postprocess(scores):\n",
|
|
||||||
" \"\"\"This function takes the scores generated by the network and \n",
|
|
||||||
" returns the class IDs in decreasing order of probability.\"\"\"\n",
|
|
||||||
" prob = softmax(scores)\n",
|
|
||||||
" prob = np.squeeze(prob)\n",
|
|
||||||
" classes = np.argsort(prob)[::-1]\n",
|
|
||||||
" return classes"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Load Test Data\n",
|
|
||||||
"\n",
|
|
||||||
"These are already in your directory from your ONNX model download (from the model zoo).\n",
|
|
||||||
"\n",
|
|
||||||
"Notice that our Model Zoo files have a .pb extension. This is because they are [protobuf files (Protocol Buffers)](https://developers.google.com/protocol-buffers/docs/pythontutorial), so we need to read in our data through our ONNX TensorProto reader into a format we can work with, like numerical arrays."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# to manipulate our arrays\n",
|
|
||||||
"import numpy as np \n",
|
|
||||||
"\n",
|
|
||||||
"# read in test data protobuf files included with the model\n",
|
|
||||||
"import onnx\n",
|
|
||||||
"from onnx import numpy_helper\n",
|
|
||||||
"\n",
|
|
||||||
"# to use parsers to read in our model/data\n",
|
|
||||||
"import json\n",
|
|
||||||
"\n",
|
|
||||||
"test_inputs = []\n",
|
|
||||||
"test_outputs = []\n",
|
|
||||||
"\n",
|
|
||||||
"# read in 1 testing images from .pb files\n",
|
|
||||||
"test_data_size = 1\n",
|
|
||||||
"\n",
|
|
||||||
"for num in np.arange(test_data_size):\n",
|
|
||||||
" input_test_data = os.path.join(model_dir, 'test_data_set_{0}'.format(num), 'input_0.pb')\n",
|
|
||||||
" output_test_data = os.path.join(model_dir, 'test_data_set_{0}'.format(num), 'output_0.pb')\n",
|
|
||||||
" \n",
|
|
||||||
" # convert protobuf tensors to np arrays using the TensorProto reader from ONNX\n",
|
|
||||||
" tensor = onnx.TensorProto()\n",
|
|
||||||
" with open(input_test_data, 'rb') as f:\n",
|
|
||||||
" tensor.ParseFromString(f.read())\n",
|
|
||||||
" \n",
|
|
||||||
" input_data = numpy_helper.to_array(tensor)\n",
|
|
||||||
" test_inputs.append(input_data)\n",
|
|
||||||
" \n",
|
|
||||||
" with open(output_test_data, 'rb') as f:\n",
|
|
||||||
" tensor.ParseFromString(f.read())\n",
|
|
||||||
" \n",
|
|
||||||
" output_data = numpy_helper.to_array(tensor)\n",
|
|
||||||
" output_processed = emotion_map(postprocess(output_data[0]))[0]\n",
|
|
||||||
" test_outputs.append(output_processed)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"nbpresent": {
|
|
||||||
"id": "c3f2f57c-7454-4d3e-b38d-b0946cf066ea"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### Show some sample images\n",
|
|
||||||
"We use `matplotlib` to plot 1 test images from the dataset."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"nbpresent": {
|
|
||||||
"id": "396d478b-34aa-4afa-9898-cdce8222a516"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"plt.figure(figsize = (20, 20))\n",
|
|
||||||
"for test_image in np.arange(test_data_size):\n",
|
|
||||||
" test_inputs[test_image].reshape(1, 64, 64)\n",
|
|
||||||
" plt.subplot(1, 8, test_image+1)\n",
|
|
||||||
" plt.axhline('')\n",
|
|
||||||
" plt.axvline('')\n",
|
|
||||||
" plt.text(x = 10, y = -10, s = test_outputs[test_image], fontsize = 18)\n",
|
|
||||||
" plt.imshow(test_inputs[test_image].reshape(64, 64), cmap = plt.cm.gray)\n",
|
|
||||||
"plt.show()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Run evaluation / prediction"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"plt.figure(figsize = (16, 6))\n",
|
|
||||||
"plt.subplot(1, 8, 1)\n",
|
|
||||||
"\n",
|
|
||||||
"plt.text(x = 0, y = -30, s = \"True Label: \", fontsize = 13, color = 'black')\n",
|
|
||||||
"plt.text(x = 0, y = -20, s = \"Result: \", fontsize = 13, color = 'black')\n",
|
|
||||||
"plt.text(x = 0, y = -10, s = \"Inference Time: \", fontsize = 13, color = 'black')\n",
|
|
||||||
"plt.text(x = 3, y = 14, s = \"Model Input\", fontsize = 12, color = 'black')\n",
|
|
||||||
"plt.text(x = 6, y = 18, s = \"(64 x 64)\", fontsize = 12, color = 'black')\n",
|
|
||||||
"plt.imshow(np.ones((28,28)), cmap=plt.cm.Greys) \n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"for i in np.arange(test_data_size):\n",
|
|
||||||
" \n",
|
|
||||||
" input_data = json.dumps({'data': test_inputs[i].tolist()})\n",
|
|
||||||
"\n",
|
|
||||||
" # predict using the deployed model\n",
|
|
||||||
" r = json.loads(aci_service.run(input_data))\n",
|
|
||||||
" \n",
|
|
||||||
" if \"error\" in r:\n",
|
|
||||||
" print(r['error'])\n",
|
|
||||||
" break\n",
|
|
||||||
" \n",
|
|
||||||
" result = r['result'][0]\n",
|
|
||||||
" time_ms = np.round(r['time_in_sec'][0] * 1000, 2)\n",
|
|
||||||
" \n",
|
|
||||||
" ground_truth = test_outputs[i]\n",
|
|
||||||
" \n",
|
|
||||||
" # compare actual value vs. the predicted values:\n",
|
|
||||||
" plt.subplot(1, 8, i+2)\n",
|
|
||||||
" plt.axhline('')\n",
|
|
||||||
" plt.axvline('')\n",
|
|
||||||
"\n",
|
|
||||||
" # use different color for misclassified sample\n",
|
|
||||||
" font_color = 'red' if ground_truth != result else 'black'\n",
|
|
||||||
" clr_map = plt.cm.Greys if ground_truth != result else plt.cm.gray\n",
|
|
||||||
"\n",
|
|
||||||
" # ground truth labels are in blue\n",
|
|
||||||
" plt.text(x = 10, y = -70, s = ground_truth, fontsize = 18, color = 'blue')\n",
|
|
||||||
" \n",
|
|
||||||
" # predictions are in black if correct, red if incorrect\n",
|
|
||||||
" plt.text(x = 10, y = -45, s = result, fontsize = 18, color = font_color)\n",
|
|
||||||
" plt.text(x = 5, y = -22, s = str(time_ms) + ' ms', fontsize = 14, color = font_color)\n",
|
|
||||||
"\n",
|
|
||||||
" \n",
|
|
||||||
" plt.imshow(test_inputs[i].reshape(64, 64), cmap = clr_map)\n",
|
|
||||||
"\n",
|
|
||||||
"plt.show()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Try classifying your own images!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Preprocessing functions take your image and format it so it can be passed\n",
|
|
||||||
"# as input into our ONNX model\n",
|
|
||||||
"\n",
|
|
||||||
"import cv2\n",
|
|
||||||
"\n",
|
|
||||||
"def rgb2gray(rgb):\n",
|
|
||||||
" \"\"\"Convert the input image into grayscale\"\"\"\n",
|
|
||||||
" return np.dot(rgb[...,:3], [0.299, 0.587, 0.114])\n",
|
|
||||||
"\n",
|
|
||||||
"def resize_img(img_to_resize):\n",
|
|
||||||
" \"\"\"Resize image to FER+ model input dimensions\"\"\"\n",
|
|
||||||
" r_img = cv2.resize(img_to_resize, dsize=(64, 64), interpolation=cv2.INTER_AREA)\n",
|
|
||||||
" r_img.resize((1, 1, 64, 64))\n",
|
|
||||||
" return r_img\n",
|
|
||||||
"\n",
|
|
||||||
"def preprocess(img_to_preprocess):\n",
|
|
||||||
" \"\"\"Resize input images and convert them to grayscale.\"\"\"\n",
|
|
||||||
" if img_to_preprocess.shape == (64, 64):\n",
|
|
||||||
" img_to_preprocess.resize((1, 1, 64, 64))\n",
|
|
||||||
" return img_to_preprocess\n",
|
|
||||||
" \n",
|
|
||||||
" grayscale = rgb2gray(img_to_preprocess)\n",
|
|
||||||
" processed_img = resize_img(grayscale)\n",
|
|
||||||
" return processed_img"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Replace the following string with your own path/test image\n",
|
|
||||||
"# Make sure your image is square and the dimensions are equal (i.e. 100 * 100 pixels or 28 * 28 pixels)\n",
|
|
||||||
"\n",
|
|
||||||
"# Any PNG or JPG image file should work\n",
|
|
||||||
"# Make sure to include the entire path with // instead of /\n",
|
|
||||||
"\n",
|
|
||||||
"# e.g. your_test_image = \"C:/Users/vinitra.swamy/Pictures/face.png\"\n",
|
|
||||||
"\n",
|
|
||||||
"your_test_image = \"<path to file>\"\n",
|
|
||||||
"\n",
|
|
||||||
"import matplotlib.image as mpimg\n",
|
|
||||||
"\n",
|
|
||||||
"if your_test_image != \"<path to file>\":\n",
|
|
||||||
" img = mpimg.imread(your_test_image)\n",
|
|
||||||
" plt.subplot(1,3,1)\n",
|
|
||||||
" plt.imshow(img, cmap = plt.cm.Greys)\n",
|
|
||||||
" print(\"Old Dimensions: \", img.shape)\n",
|
|
||||||
" img = preprocess(img)\n",
|
|
||||||
" print(\"New Dimensions: \", img.shape)\n",
|
|
||||||
"else:\n",
|
|
||||||
" img = None"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"if img is None:\n",
|
|
||||||
" print(\"Add the path for your image data.\")\n",
|
|
||||||
"else:\n",
|
|
||||||
" input_data = json.dumps({'data': img.tolist()})\n",
|
|
||||||
"\n",
|
|
||||||
" try:\n",
|
|
||||||
" r = json.loads(aci_service.run(input_data))\n",
|
|
||||||
" result = r['result'][0]\n",
|
|
||||||
" time_ms = np.round(r['time_in_sec'][0] * 1000, 2)\n",
|
|
||||||
" except KeyError as e:\n",
|
|
||||||
" print(str(e))\n",
|
|
||||||
"\n",
|
|
||||||
" plt.figure(figsize = (16, 6))\n",
|
|
||||||
" plt.subplot(1,8,1)\n",
|
|
||||||
" plt.axhline('')\n",
|
|
||||||
" plt.axvline('')\n",
|
|
||||||
" plt.text(x = -10, y = -40, s = \"Model prediction: \", fontsize = 14)\n",
|
|
||||||
" plt.text(x = -10, y = -25, s = \"Inference time: \", fontsize = 14)\n",
|
|
||||||
" plt.text(x = 100, y = -40, s = str(result), fontsize = 14)\n",
|
|
||||||
" plt.text(x = 100, y = -25, s = str(time_ms) + \" ms\", fontsize = 14)\n",
|
|
||||||
" plt.text(x = -10, y = -10, s = \"Model Input image: \", fontsize = 14)\n",
|
|
||||||
" plt.imshow(img.reshape((64, 64)), cmap = plt.cm.gray) \n",
|
|
||||||
" "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# remember to delete your service after you are done using it!\n",
|
|
||||||
"\n",
|
|
||||||
"aci_service.delete()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Conclusion\n",
|
|
||||||
"\n",
|
|
||||||
"Congratulations!\n",
|
|
||||||
"\n",
|
|
||||||
"In this tutorial, you have:\n",
|
|
||||||
"- familiarized yourself with ONNX Runtime inference and the pretrained models in the ONNX model zoo\n",
|
|
||||||
"- understood a state-of-the-art convolutional neural net image classification model (FER+ in ONNX) and deployed it in the Azure ML cloud\n",
|
|
||||||
"- ensured that your deep learning model is working perfectly (in the cloud) on test data, and checked it against some of your own!\n",
|
|
||||||
"\n",
|
|
||||||
"Next steps:\n",
|
|
||||||
"- If you have not already, check out another interesting ONNX/AML application that lets you set up a state-of-the-art [handwritten image classification model (MNIST)](https://github.com/Azure/MachineLearningNotebooks/blob/master/how-to-use-azureml/deployment/onnx/onnx-inference-mnist-deploy.ipynb) in the cloud! This tutorial deploys a pre-trained ONNX Computer Vision model for handwritten digit classification in an Azure ML virtual machine.\n",
|
|
||||||
"- Keep an eye out for an updated version of this tutorial that uses ONNX Runtime GPU.\n",
|
|
||||||
"- Contribute to our [open source ONNX repository on github](http://github.com/onnx/onnx) and/or add to our [ONNX model zoo](http://github.com/onnx/models)"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "viswamy"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"category": "deployment",
|
|
||||||
"compute": [
|
|
||||||
"Local"
|
|
||||||
],
|
|
||||||
"datasets": [
|
|
||||||
"Emotion FER"
|
|
||||||
],
|
|
||||||
"deployment": [
|
|
||||||
"Azure Container Instance"
|
|
||||||
],
|
|
||||||
"exclude_from_index": false,
|
|
||||||
"framework": [
|
|
||||||
"ONNX"
|
|
||||||
],
|
|
||||||
"friendly_name": "Deploy Facial Expression Recognition (FER+) with ONNX Runtime",
|
|
||||||
"index_order": 2,
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3.8 - AzureML",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python38-azureml"
|
|
||||||
},
|
|
||||||
"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.6.5"
|
|
||||||
},
|
|
||||||
"msauthor": "vinitra.swamy",
|
|
||||||
"star_tag": [],
|
|
||||||
"tags": [
|
|
||||||
"ONNX Model Zoo"
|
|
||||||
],
|
|
||||||
"task": "Facial Expression Recognition"
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
name: onnx-inference-facial-expression-recognition-deploy
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
- azureml-widgets
|
|
||||||
- matplotlib
|
|
||||||
- numpy
|
|
||||||
- onnx<1.7.0
|
|
||||||
- opencv-python-headless
|
|
||||||
@@ -1,778 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Copyright (c) Microsoft Corporation. All rights reserved. \n",
|
|
||||||
"Licensed under the MIT License."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Handwritten Digit Classification (MNIST) using ONNX Runtime on Azure ML\n",
|
|
||||||
"\n",
|
|
||||||
"This example shows how to deploy an image classification neural network using the Modified National Institute of Standards and Technology ([MNIST](http://yann.lecun.com/exdb/mnist/)) dataset and Open Neural Network eXchange format ([ONNX](http://aka.ms/onnxdocarticle)) on the Azure Machine Learning platform. MNIST is a popular dataset consisting of 70,000 grayscale images. Each image is a handwritten digit of 28x28 pixels, representing number from 0 to 9. This tutorial will show you how to deploy a MNIST model from the [ONNX model zoo](https://github.com/onnx/models), use it to make predictions using ONNX Runtime Inference, and deploy it as a web service in Azure.\n",
|
|
||||||
"\n",
|
|
||||||
"Throughout this tutorial, we will be referring to ONNX, a neural network exchange format used to represent deep learning models. With ONNX, AI developers can more easily move models between state-of-the-art tools (CNTK, PyTorch, Caffe, MXNet, TensorFlow) and choose the combination that is best for them. ONNX is developed and supported by a community of partners including Microsoft AI, Facebook, and Amazon. For more information, explore the [ONNX website](http://onnx.ai) and [open source files](https://github.com/onnx).\n",
|
|
||||||
"\n",
|
|
||||||
"[ONNX Runtime](https://aka.ms/onnxruntime-python) is the runtime engine that enables evaluation of trained machine learning (Traditional ML and Deep Learning) models with high performance and low resource utilization.\n",
|
|
||||||
"\n",
|
|
||||||
"#### Tutorial Objectives:\n",
|
|
||||||
"\n",
|
|
||||||
"- Describe the MNIST dataset and pretrained Convolutional Neural Net ONNX model, stored in the ONNX model zoo.\n",
|
|
||||||
"- Deploy and run the pretrained MNIST ONNX model on an Azure Machine Learning instance\n",
|
|
||||||
"- Predict labels for test set data points in the cloud using ONNX Runtime and Azure ML"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Prerequisites\n",
|
|
||||||
"\n",
|
|
||||||
"### 1. Install Azure ML SDK and create a new workspace\n",
|
|
||||||
"If you are using an Azure Machine Learning Notebook VM, you are all set. Otherwise, please follow [Azure ML configuration notebook](../../../configuration.ipynb) to set up your environment.\n",
|
|
||||||
"\n",
|
|
||||||
"### 2. Install additional packages needed for this tutorial notebook\n",
|
|
||||||
"You need to install the popular plotting library `matplotlib`, the image manipulation library `opencv`, and the `onnx` library in the conda environment where Azure Maching Learning SDK is installed. \n",
|
|
||||||
"\n",
|
|
||||||
"```sh\n",
|
|
||||||
"(myenv) $ pip install matplotlib onnx opencv-python\n",
|
|
||||||
"```\n",
|
|
||||||
"\n",
|
|
||||||
"**Debugging tip**: Make sure that you run the \"jupyter notebook\" command to launch this notebook after activating your virtual environment. Choose the respective Python kernel for your new virtual environment using the `Kernel > Change Kernel` menu above. If you have completed the steps correctly, the upper right corner of your screen should state `Python [conda env:myenv]` instead of `Python [default]`.\n",
|
|
||||||
"\n",
|
|
||||||
"### 3. Download sample data and pre-trained ONNX model from ONNX Model Zoo.\n",
|
|
||||||
"\n",
|
|
||||||
"In the following lines of code, we download [the trained ONNX MNIST model and corresponding test data](https://github.com/onnx/models/tree/master/vision/classification/mnist) and place them in the same folder as this tutorial notebook. For more information about the MNIST dataset, please visit [Yan LeCun's website](http://yann.lecun.com/exdb/mnist/)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# urllib is a built-in Python library to download files from URLs\n",
|
|
||||||
"\n",
|
|
||||||
"# Objective: retrieve the latest version of the ONNX MNIST model files from the\n",
|
|
||||||
"# ONNX Model Zoo and save it in the same folder as this tutorial\n",
|
|
||||||
"\n",
|
|
||||||
"import urllib.request\n",
|
|
||||||
"import os\n",
|
|
||||||
"\n",
|
|
||||||
"onnx_model_url = \"https://github.com/onnx/models/blob/main/vision/classification/mnist/model/mnist-7.tar.gz?raw=true\"\n",
|
|
||||||
"\n",
|
|
||||||
"urllib.request.urlretrieve(onnx_model_url, filename=\"mnist-7.tar.gz\")\n",
|
|
||||||
"os.mkdir(\"mnist\")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# the ! magic command tells our jupyter notebook kernel to run the following line of \n",
|
|
||||||
"# code from the command line instead of the notebook kernel\n",
|
|
||||||
"\n",
|
|
||||||
"# We use tar and xvcf to unzip the files we just retrieved from the ONNX model zoo\n",
|
|
||||||
"\n",
|
|
||||||
"!tar xvzf mnist-7.tar.gz -C mnist"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Deploy a VM with your ONNX model in the Cloud\n",
|
|
||||||
"\n",
|
|
||||||
"### Load Azure ML workspace\n",
|
|
||||||
"\n",
|
|
||||||
"We begin by instantiating a workspace object from the existing workspace created earlier in the configuration notebook."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Check core SDK version number\n",
|
|
||||||
"import azureml.core\n",
|
|
||||||
"\n",
|
|
||||||
"print(\"SDK version:\", azureml.core.VERSION)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Workspace\n",
|
|
||||||
"\n",
|
|
||||||
"ws = Workspace.from_config()\n",
|
|
||||||
"print(ws.name, ws.resource_group, ws.location, sep = '\\n')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Registering your model with Azure ML"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"model_dir = \"mnist/model\" # replace this with the location of your model files\n",
|
|
||||||
"\n",
|
|
||||||
"# leave as is if it's in the same folder as this notebook"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import Model\n",
|
|
||||||
"\n",
|
|
||||||
"model = Model.register(workspace = ws,\n",
|
|
||||||
" model_path = model_dir + \"/\" + \"model.onnx\",\n",
|
|
||||||
" model_name = \"mnist_1\",\n",
|
|
||||||
" tags = {\"onnx\": \"demo\"},\n",
|
|
||||||
" description = \"MNIST image classification CNN from ONNX Model Zoo\",)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Optional: Displaying your registered models\n",
|
|
||||||
"\n",
|
|
||||||
"This step is not required, so feel free to skip it."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"models = ws.models\n",
|
|
||||||
"for name, m in models.items():\n",
|
|
||||||
" print(\"Name:\", name,\"\\tVersion:\", m.version, \"\\tDescription:\", m.description, m.tags)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"nbpresent": {
|
|
||||||
"id": "c3f2f57c-7454-4d3e-b38d-b0946cf066ea"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### ONNX MNIST Model Methodology\n",
|
|
||||||
"\n",
|
|
||||||
"The image classification model we are using is pre-trained using Microsoft's deep learning cognitive toolkit, [CNTK](https://github.com/Microsoft/CNTK), from the [ONNX model zoo](http://github.com/onnx/models). The model zoo has many other models that can be deployed on cloud providers like AzureML without any additional training. To ensure that our cloud deployed model works, we use testing data from the famous MNIST data set, provided as part of the [trained MNIST model](https://github.com/onnx/models/tree/master/vision/classification/mnist) in the ONNX model zoo.\n",
|
|
||||||
"\n",
|
|
||||||
"***Input: Handwritten Images from MNIST Dataset***\n",
|
|
||||||
"\n",
|
|
||||||
"***Task: Classify each MNIST image into an appropriate digit***\n",
|
|
||||||
"\n",
|
|
||||||
"***Output: Digit prediction for input image***\n",
|
|
||||||
"\n",
|
|
||||||
"Run the cell below to look at some of the sample images from the MNIST dataset that we used to train this ONNX model. Remember, once the application is deployed in Azure ML, you can use your own images as input for the model to classify!"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# for images and plots in this notebook\n",
|
|
||||||
"import matplotlib.pyplot as plt \n",
|
|
||||||
"from IPython.display import Image\n",
|
|
||||||
"\n",
|
|
||||||
"# display images inline\n",
|
|
||||||
"%matplotlib inline"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"Image(url=\"http://3.bp.blogspot.com/_UpN7DfJA0j4/TJtUBWPk0SI/AAAAAAAAABY/oWPMtmqJn3k/s1600/mnist_originals.png\", width=200, height=200)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Specify our Score and Environment Files"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"We are now going to deploy our ONNX Model on AML with inference in ONNX Runtime. We begin by writing a score.py file, which will help us run the model in our Azure ML virtual machine (VM), and then specify our environment by writing a yml file. You will also notice that we import the onnxruntime library to do runtime inference on our ONNX models (passing in input and evaluating out model's predicted output). More information on the API and commands can be found in the [ONNX Runtime documentation](https://aka.ms/onnxruntime).\n",
|
|
||||||
"\n",
|
|
||||||
"### Write Score File\n",
|
|
||||||
"\n",
|
|
||||||
"A score file is what tells our Azure cloud service what to do. After initializing our model using azureml.core.model, we start an ONNX Runtime inference session to evaluate the data passed in on our function calls."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%writefile score.py\n",
|
|
||||||
"import json\n",
|
|
||||||
"import numpy as np\n",
|
|
||||||
"import onnxruntime\n",
|
|
||||||
"import sys\n",
|
|
||||||
"import os\n",
|
|
||||||
"import time\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def init():\n",
|
|
||||||
" global session, input_name, output_name\n",
|
|
||||||
" # AZUREML_MODEL_DIR is an environment variable created during deployment.\n",
|
|
||||||
" # It is the path to the model folder (./azureml-models/$MODEL_NAME/$VERSION)\n",
|
|
||||||
" # For multiple models, it points to the folder containing all deployed models (./azureml-models)\n",
|
|
||||||
" model = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'model.onnx')\n",
|
|
||||||
" session = onnxruntime.InferenceSession(model, None)\n",
|
|
||||||
" input_name = session.get_inputs()[0].name\n",
|
|
||||||
" output_name = session.get_outputs()[0].name \n",
|
|
||||||
" \n",
|
|
||||||
"\n",
|
|
||||||
"def preprocess(input_data_json):\n",
|
|
||||||
" # convert the JSON data into the tensor input\n",
|
|
||||||
" return np.array(json.loads(input_data_json)['data']).astype('float32')\n",
|
|
||||||
"\n",
|
|
||||||
"def postprocess(result):\n",
|
|
||||||
" # We use argmax to pick the highest confidence label\n",
|
|
||||||
" return int(np.argmax(np.array(result).squeeze(), axis=0))\n",
|
|
||||||
" \n",
|
|
||||||
"def run(input_data):\n",
|
|
||||||
"\n",
|
|
||||||
" try:\n",
|
|
||||||
" # load in our data, convert to readable format\n",
|
|
||||||
" data = preprocess(input_data)\n",
|
|
||||||
" \n",
|
|
||||||
" # start timer\n",
|
|
||||||
" start = time.time()\n",
|
|
||||||
" \n",
|
|
||||||
" r = session.run([output_name], {input_name: data})\n",
|
|
||||||
" \n",
|
|
||||||
" #end timer\n",
|
|
||||||
" end = time.time()\n",
|
|
||||||
" \n",
|
|
||||||
" result = postprocess(r)\n",
|
|
||||||
" result_dict = {\"result\": result,\n",
|
|
||||||
" \"time_in_sec\": end - start}\n",
|
|
||||||
" except Exception as e:\n",
|
|
||||||
" result_dict = {\"error\": str(e)}\n",
|
|
||||||
" \n",
|
|
||||||
" return result_dict\n",
|
|
||||||
"\n",
|
|
||||||
"def choose_class(result_prob):\n",
|
|
||||||
" \"\"\"We use argmax to determine the right label to choose from our output\"\"\"\n",
|
|
||||||
" return int(np.argmax(result_prob, axis=0))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Write Environment File\n",
|
|
||||||
"\n",
|
|
||||||
"This step creates a YAML environment file that specifies which dependencies we would like to see in our Linux Virtual Machine. Please note that you must indicate azureml-defaults with verion >= 1.0.45 as a pip dependency, because it contains the functionality needed to host the model as a web service."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.conda_dependencies import CondaDependencies \n",
|
|
||||||
"\n",
|
|
||||||
"myenv = CondaDependencies.create(pip_packages=[\"numpy\", \"onnxruntime\", \"azureml-core\", \"azureml-defaults\"])\n",
|
|
||||||
"\n",
|
|
||||||
"with open(\"myenv.yml\",\"w\") as f:\n",
|
|
||||||
" f.write(myenv.serialize_to_string())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Create Inference Configuration"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import InferenceConfig\n",
|
|
||||||
"from azureml.core.environment import Environment\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"myenv = Environment.from_conda_specification(name=\"myenv\", file_path=\"myenv.yml\")\n",
|
|
||||||
"inference_config = InferenceConfig(entry_script=\"score.py\", environment=myenv)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Deploy the model"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.webservice import AciWebservice\n",
|
|
||||||
"\n",
|
|
||||||
"aciconfig = AciWebservice.deploy_configuration(cpu_cores = 1, \n",
|
|
||||||
" memory_gb = 1, \n",
|
|
||||||
" tags = {'demo': 'onnx'}, \n",
|
|
||||||
" description = 'ONNX for mnist model')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The following cell will likely take a few minutes to run."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"aci_service_name = 'onnx-demo-mnist'\n",
|
|
||||||
"print(\"Service\", aci_service_name)\n",
|
|
||||||
"aci_service = Model.deploy(ws, aci_service_name, [model], inference_config, aciconfig)\n",
|
|
||||||
"aci_service.wait_for_deployment(True)\n",
|
|
||||||
"print(aci_service.state)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"if aci_service.state != 'Healthy':\n",
|
|
||||||
" # run this command for debugging.\n",
|
|
||||||
" print(aci_service.get_logs())\n",
|
|
||||||
"\n",
|
|
||||||
" # If your deployment fails, make sure to delete your aci_service or rename your service before trying again!\n",
|
|
||||||
" # aci_service.delete()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Success!\n",
|
|
||||||
"\n",
|
|
||||||
"If you've made it this far, you've deployed a working VM with a handwritten digit classifier running in the cloud using Azure ML. Congratulations!\n",
|
|
||||||
"\n",
|
|
||||||
"You can get the URL for the webservice with the code below. Let's now see how well our model deals with our test images."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"print(aci_service.scoring_uri)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Testing and Evaluation\n",
|
|
||||||
"\n",
|
|
||||||
"### Load Test Data\n",
|
|
||||||
"\n",
|
|
||||||
"These are already in your directory from your ONNX model download (from the model zoo).\n",
|
|
||||||
"\n",
|
|
||||||
"Notice that our Model Zoo files have a .pb extension. This is because they are [protobuf files (Protocol Buffers)](https://developers.google.com/protocol-buffers/docs/pythontutorial), so we need to read in our data through our ONNX TensorProto reader into a format we can work with, like numerical arrays."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# to manipulate our arrays\n",
|
|
||||||
"import numpy as np \n",
|
|
||||||
"\n",
|
|
||||||
"# read in test data protobuf files included with the model\n",
|
|
||||||
"import onnx\n",
|
|
||||||
"from onnx import numpy_helper\n",
|
|
||||||
"\n",
|
|
||||||
"# to use parsers to read in our model/data\n",
|
|
||||||
"import json\n",
|
|
||||||
"\n",
|
|
||||||
"test_inputs = []\n",
|
|
||||||
"test_outputs = []\n",
|
|
||||||
"\n",
|
|
||||||
"# read in 1 testing images from .pb files\n",
|
|
||||||
"test_data_size = 1\n",
|
|
||||||
"\n",
|
|
||||||
"for i in np.arange(test_data_size):\n",
|
|
||||||
" input_test_data = os.path.join(model_dir, 'test_data_set_{0}'.format(i), 'input_0.pb')\n",
|
|
||||||
" output_test_data = os.path.join(model_dir, 'test_data_set_{0}'.format(i), 'output_0.pb')\n",
|
|
||||||
" \n",
|
|
||||||
" # convert protobuf tensors to np arrays using the TensorProto reader from ONNX\n",
|
|
||||||
" tensor = onnx.TensorProto()\n",
|
|
||||||
" with open(input_test_data, 'rb') as f:\n",
|
|
||||||
" tensor.ParseFromString(f.read())\n",
|
|
||||||
" \n",
|
|
||||||
" input_data = numpy_helper.to_array(tensor)\n",
|
|
||||||
" test_inputs.append(input_data)\n",
|
|
||||||
" \n",
|
|
||||||
" with open(output_test_data, 'rb') as f:\n",
|
|
||||||
" tensor.ParseFromString(f.read())\n",
|
|
||||||
" \n",
|
|
||||||
" output_data = numpy_helper.to_array(tensor)\n",
|
|
||||||
" test_outputs.append(output_data)\n",
|
|
||||||
" \n",
|
|
||||||
"if len(test_inputs) == test_data_size:\n",
|
|
||||||
" print('Test data loaded successfully.')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {
|
|
||||||
"nbpresent": {
|
|
||||||
"id": "c3f2f57c-7454-4d3e-b38d-b0946cf066ea"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source": [
|
|
||||||
"### Show some sample images\n",
|
|
||||||
"We use `matplotlib` to plot 1 test images from the dataset."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"nbpresent": {
|
|
||||||
"id": "396d478b-34aa-4afa-9898-cdce8222a516"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"plt.figure(figsize = (16, 6))\n",
|
|
||||||
"for test_image in np.arange(test_data_size):\n",
|
|
||||||
" plt.subplot(1, 15, test_image+1)\n",
|
|
||||||
" plt.axhline('')\n",
|
|
||||||
" plt.axvline('')\n",
|
|
||||||
" plt.imshow(test_inputs[test_image].reshape(28, 28), cmap = plt.cm.Greys)\n",
|
|
||||||
"plt.show()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Run evaluation / prediction"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"plt.figure(figsize = (16, 6))\n",
|
|
||||||
"plt.subplot(1, 8, 1)\n",
|
|
||||||
"\n",
|
|
||||||
"plt.text(x = 0, y = -30, s = \"True Label: \", fontsize = 13, color = 'black')\n",
|
|
||||||
"plt.text(x = 0, y = -20, s = \"Result: \", fontsize = 13, color = 'black')\n",
|
|
||||||
"plt.text(x = 0, y = -10, s = \"Inference Time: \", fontsize = 13, color = 'black')\n",
|
|
||||||
"plt.text(x = 3, y = 14, s = \"Model Input\", fontsize = 12, color = 'black')\n",
|
|
||||||
"plt.text(x = 6, y = 18, s = \"(28 x 28)\", fontsize = 12, color = 'black')\n",
|
|
||||||
"plt.imshow(np.ones((28,28)), cmap=plt.cm.Greys) \n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"for i in np.arange(test_data_size):\n",
|
|
||||||
" \n",
|
|
||||||
" input_data = json.dumps({'data': test_inputs[i].tolist()})\n",
|
|
||||||
" \n",
|
|
||||||
" # predict using the deployed model\n",
|
|
||||||
" r = aci_service.run(input_data)\n",
|
|
||||||
" \n",
|
|
||||||
" if \"error\" in r:\n",
|
|
||||||
" print(r['error'])\n",
|
|
||||||
" break\n",
|
|
||||||
" \n",
|
|
||||||
" result = r['result']\n",
|
|
||||||
" time_ms = np.round(r['time_in_sec'] * 1000, 2)\n",
|
|
||||||
" \n",
|
|
||||||
" ground_truth = int(np.argmax(test_outputs[i]))\n",
|
|
||||||
" \n",
|
|
||||||
" # compare actual value vs. the predicted values:\n",
|
|
||||||
" plt.subplot(1, 8, i+2)\n",
|
|
||||||
" plt.axhline('')\n",
|
|
||||||
" plt.axvline('')\n",
|
|
||||||
"\n",
|
|
||||||
" # use different color for misclassified sample\n",
|
|
||||||
" font_color = 'red' if ground_truth != result else 'black'\n",
|
|
||||||
" clr_map = plt.cm.gray if ground_truth != result else plt.cm.Greys\n",
|
|
||||||
"\n",
|
|
||||||
" # ground truth labels are in blue\n",
|
|
||||||
" plt.text(x = 10, y = -30, s = ground_truth, fontsize = 18, color = 'blue')\n",
|
|
||||||
" \n",
|
|
||||||
" # predictions are in black if correct, red if incorrect\n",
|
|
||||||
" plt.text(x = 10, y = -20, s = result, fontsize = 18, color = font_color)\n",
|
|
||||||
" plt.text(x = 5, y = -10, s = str(time_ms) + ' ms', fontsize = 14, color = font_color)\n",
|
|
||||||
"\n",
|
|
||||||
" \n",
|
|
||||||
" plt.imshow(test_inputs[i].reshape(28, 28), cmap = clr_map)\n",
|
|
||||||
"\n",
|
|
||||||
"plt.show()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Try classifying your own images!\n",
|
|
||||||
"\n",
|
|
||||||
"Create your own handwritten image and pass it into the model."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Preprocessing functions take your image and format it so it can be passed\n",
|
|
||||||
"# as input into our ONNX model\n",
|
|
||||||
"\n",
|
|
||||||
"import cv2\n",
|
|
||||||
"\n",
|
|
||||||
"def rgb2gray(rgb):\n",
|
|
||||||
" \"\"\"Convert the input image into grayscale\"\"\"\n",
|
|
||||||
" return np.dot(rgb[...,:3], [0.299, 0.587, 0.114])\n",
|
|
||||||
"\n",
|
|
||||||
"def resize_img(img_to_resize):\n",
|
|
||||||
" \"\"\"Resize image to MNIST model input dimensions\"\"\"\n",
|
|
||||||
" r_img = cv2.resize(img_to_resize, dsize=(28, 28), interpolation=cv2.INTER_AREA)\n",
|
|
||||||
" r_img.resize((1, 1, 28, 28))\n",
|
|
||||||
" return r_img\n",
|
|
||||||
"\n",
|
|
||||||
"def preprocess(img_to_preprocess):\n",
|
|
||||||
" \"\"\"Resize input images and convert them to grayscale.\"\"\"\n",
|
|
||||||
" if img_to_preprocess.shape == (28, 28):\n",
|
|
||||||
" img_to_preprocess.resize((1, 1, 28, 28))\n",
|
|
||||||
" return img_to_preprocess\n",
|
|
||||||
" \n",
|
|
||||||
" grayscale = rgb2gray(img_to_preprocess)\n",
|
|
||||||
" processed_img = resize_img(grayscale)\n",
|
|
||||||
" return processed_img"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Replace this string with your own path/test image\n",
|
|
||||||
"# Make sure your image is square and the dimensions are equal (i.e. 100 * 100 pixels or 28 * 28 pixels)\n",
|
|
||||||
"\n",
|
|
||||||
"# Any PNG or JPG image file should work\n",
|
|
||||||
"\n",
|
|
||||||
"your_test_image = \"<path to file>\"\n",
|
|
||||||
"\n",
|
|
||||||
"# e.g. your_test_image = \"C:/Users/vinitra.swamy/Pictures/handwritten_digit.png\"\n",
|
|
||||||
"\n",
|
|
||||||
"import matplotlib.image as mpimg\n",
|
|
||||||
"\n",
|
|
||||||
"if your_test_image != \"<path to file>\":\n",
|
|
||||||
" img = mpimg.imread(your_test_image)\n",
|
|
||||||
" plt.subplot(1,3,1)\n",
|
|
||||||
" plt.imshow(img, cmap = plt.cm.Greys)\n",
|
|
||||||
" print(\"Old Dimensions: \", img.shape)\n",
|
|
||||||
" img = preprocess(img)\n",
|
|
||||||
" print(\"New Dimensions: \", img.shape)\n",
|
|
||||||
"else:\n",
|
|
||||||
" img = None"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"if img is None:\n",
|
|
||||||
" print(\"Add the path for your image data.\")\n",
|
|
||||||
"else:\n",
|
|
||||||
" input_data = json.dumps({'data': img.tolist()})\n",
|
|
||||||
"\n",
|
|
||||||
" try:\n",
|
|
||||||
" r = aci_service.run(input_data)\n",
|
|
||||||
" result = r['result']\n",
|
|
||||||
" time_ms = np.round(r['time_in_sec'] * 1000, 2)\n",
|
|
||||||
" except KeyError as e:\n",
|
|
||||||
" print(str(e))\n",
|
|
||||||
"\n",
|
|
||||||
" plt.figure(figsize = (16, 6))\n",
|
|
||||||
" plt.subplot(1, 15,1)\n",
|
|
||||||
" plt.axhline('')\n",
|
|
||||||
" plt.axvline('')\n",
|
|
||||||
" plt.text(x = -100, y = -20, s = \"Model prediction: \", fontsize = 14)\n",
|
|
||||||
" plt.text(x = -100, y = -10, s = \"Inference time: \", fontsize = 14)\n",
|
|
||||||
" plt.text(x = 0, y = -20, s = str(result), fontsize = 14)\n",
|
|
||||||
" plt.text(x = 0, y = -10, s = str(time_ms) + \" ms\", fontsize = 14)\n",
|
|
||||||
" plt.text(x = -100, y = 14, s = \"Input image: \", fontsize = 14)\n",
|
|
||||||
" plt.imshow(img.reshape(28, 28), cmap = plt.cm.gray) "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Optional: How does our ONNX MNIST model work? \n",
|
|
||||||
"#### A brief explanation of Convolutional Neural Networks\n",
|
|
||||||
"\n",
|
|
||||||
"A [convolutional neural network](https://en.wikipedia.org/wiki/Convolutional_neural_network) (CNN, or ConvNet) is a type of [feed-forward](https://en.wikipedia.org/wiki/Feedforward_neural_network) artificial neural network made up of neurons that have learnable weights and biases. The CNNs take advantage of the spatial nature of the data. In nature, we perceive different objects by their shapes, size and colors. For example, objects in a natural scene are typically edges, corners/vertices (defined by two of more edges), color patches etc. These primitives are often identified using different detectors (e.g., edge detection, color detector) or combination of detectors interacting to facilitate image interpretation (object classification, region of interest detection, scene description etc.) in real world vision related tasks. These detectors are also known as filters. Convolution is a mathematical operator that takes an image and a filter as input and produces a filtered output (representing say edges, corners, or colors in the input image). \n",
|
|
||||||
"\n",
|
|
||||||
"Historically, these filters are a set of weights that were often hand crafted or modeled with mathematical functions (e.g., [Gaussian](https://en.wikipedia.org/wiki/Gaussian_filter) / [Laplacian](http://homepages.inf.ed.ac.uk/rbf/HIPR2/log.htm) / [Canny](https://en.wikipedia.org/wiki/Canny_edge_detector) filter). The filter outputs are mapped through non-linear activation functions mimicking human brain cells called [neurons](https://en.wikipedia.org/wiki/Neuron). Popular deep CNNs or ConvNets (such as [AlexNet](https://en.wikipedia.org/wiki/AlexNet), [VGG](https://arxiv.org/abs/1409.1556), [Inception](http://www.cv-foundation.org/openaccess/content_cvpr_2015/papers/Szegedy_Going_Deeper_With_2015_CVPR_paper.pdf), [ResNet](https://arxiv.org/pdf/1512.03385v1.pdf)) that are used for various [computer vision](https://en.wikipedia.org/wiki/Computer_vision) tasks have many of these architectural primitives (inspired from biology). \n",
|
|
||||||
"\n",
|
|
||||||
"### Convolution Layer\n",
|
|
||||||
"\n",
|
|
||||||
"A convolution layer is a set of filters. Each filter is defined by a weight (**W**) matrix, and bias ($b$).\n",
|
|
||||||
"\n",
|
|
||||||
"These filters are scanned across the image performing the dot product between the weights and corresponding input value ($x$). The bias value is added to the output of the dot product and the resulting sum is optionally mapped through an activation function."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Model Description\n",
|
|
||||||
"\n",
|
|
||||||
"The MNIST model from the ONNX Model Zoo uses maxpooling to update the weights in its convolutions, summarized by the graphic below. You can see the entire workflow of our pre-trained model in the following image, with our input images and our output probabilities of each of our 10 labels. If you're interested in exploring the logic behind creating a Deep Learning model further, please look at the [training tutorial for our ONNX MNIST Convolutional Neural Network](https://github.com/Microsoft/CNTK/blob/master/Tutorials/CNTK_103D_MNIST_ConvolutionalNeuralNetwork.ipynb). "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# remember to delete your service after you are done using it!\n",
|
|
||||||
"\n",
|
|
||||||
"aci_service.delete()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Conclusion\n",
|
|
||||||
"\n",
|
|
||||||
"Congratulations!\n",
|
|
||||||
"\n",
|
|
||||||
"In this tutorial, you have:\n",
|
|
||||||
"- familiarized yourself with ONNX Runtime inference and the pretrained models in the ONNX model zoo\n",
|
|
||||||
"- understood a state-of-the-art convolutional neural net image classification model (MNIST in ONNX) and deployed it in Azure ML cloud\n",
|
|
||||||
"- ensured that your deep learning model is working perfectly (in the cloud) on test data, and checked it against some of your own!\n",
|
|
||||||
"\n",
|
|
||||||
"Next steps:\n",
|
|
||||||
"- Check out another interesting application based on a Microsoft Research computer vision paper that lets you set up a [facial emotion recognition model](https://github.com/Azure/MachineLearningNotebooks/blob/master/how-to-use-azureml/deployment/onnx/onnx-inference-facial-expression-recognition-deploy.ipynb) in the cloud! This tutorial deploys a pre-trained ONNX Computer Vision model in an Azure ML virtual machine.\n",
|
|
||||||
"- Contribute to our [open source ONNX repository on github](http://github.com/onnx/onnx) and/or add to our [ONNX model zoo](http://github.com/onnx/models)"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "viswamy"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"category": "deployment",
|
|
||||||
"compute": [
|
|
||||||
"Local"
|
|
||||||
],
|
|
||||||
"datasets": [
|
|
||||||
"MNIST"
|
|
||||||
],
|
|
||||||
"deployment": [
|
|
||||||
"Azure Container Instance"
|
|
||||||
],
|
|
||||||
"exclude_from_index": false,
|
|
||||||
"framework": [
|
|
||||||
"ONNX"
|
|
||||||
],
|
|
||||||
"friendly_name": "Deploy MNIST digit recognition with ONNX Runtime",
|
|
||||||
"index_order": 1,
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3.8 - AzureML",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python38-azureml"
|
|
||||||
},
|
|
||||||
"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.6.5"
|
|
||||||
},
|
|
||||||
"msauthor": "vinitra.swamy",
|
|
||||||
"star_tag": [],
|
|
||||||
"tags": [
|
|
||||||
"ONNX Model Zoo"
|
|
||||||
],
|
|
||||||
"task": "Image Classification"
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
name: onnx-inference-mnist-deploy
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
- azureml-widgets
|
|
||||||
- matplotlib
|
|
||||||
- numpy
|
|
||||||
- onnx<1.7.0
|
|
||||||
- opencv-python-headless
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"inputs": {"Input3": {"dims": ["1", "1", "28", "28"], "dataType": 1, "rawData": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAPwAAQEAAAAAAAAAAAAAAgEAAAABAAAAAAAAAMEEAAAAAAAAAAAAAYEEAAIA/AAAAAAAAmEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEEAAAAAAAAAAAAA4EAAAAAAAACAPwAAIEEAAAAAAAAAQAAAAEAAAIBBAAAAAAAAQEAAAEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4EAAAABBAAAAAAAAAEEAAAAAAAAAAAAAAEEAAAAAAAAAAAAAmEEAAAAAAAAAAAAAgD8AAKhBAAAAAAAAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAMEEAAAAAAAAAAAAAIEEAAEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQQQAAAAAAAHBBAAAgQQAA0EEAAAhCAACIQQAAmkIAADVDAAAyQwAADEIAAIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQwAAfkMAAHpDAAB7QwAAc0MAAHxDAAB8QwAAf0MAADRCAADAQAAAAAAAAKBAAAAAAAAAEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOBAAACQQgAATUMAAH9DAABuQwAAc0MAAH9DAAB+QwAAe0MAAHhDAABJQwAARkMAAGRCAAAAAAAAmEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWkMAAH9DAABxQwAAf0MAAHlDAAB6QwAAe0MAAHpDAAB/QwAAf0MAAHJDAABgQwAAREIAAAAAAABAQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgD8AAABAAABAQAAAAEAAAABAAACAPwAAAAAAAIJCAABkQwAAf0MAAH5DAAB0QwAA7kIAAAhCAAAkQgAA3EIAAHpDAAB/QwAAeEMAAPhCAACgQQAAAAAAAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBBAAAAAAAAeEIAAM5CAADiQgAA6kIAAAhCAAAAAAAAAAAAAAAAAABIQwAAdEMAAH9DAAB/QwAAAAAAAEBBAAAAAAAAAAAAAAAAAAAAAAAAAEAAAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAABAAAAAAAAAAAAAAABAAACAQAAAAAAAADBBAAAAAAAA4EAAAMBAAAAAAAAAlkIAAHRDAAB/QwAAf0MAAIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAQAAAQEAAAIBAAACAQAAAAAAAAGBBAAAAAAAAAAAAAAAAAAAQQQAAAAAAAABAAAAAAAAAAAAAAAhCAAB/QwAAf0MAAH1DAAAgQQAAIEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAQAAAQEAAAABAAAAAAAAAAAAAAEBAAAAAQAAAAAAAAFBBAAAwQQAAAAAAAAAAAAAAAAAAwEAAAEBBAADGQgAAf0MAAH5DAAB4QwAAcEEAAEBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAoEAAAMBAAAAwQQAAAAAAAAAAAACIQQAAOEMAAHdDAAB/QwAAc0MAAFBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAACAQAAAgEAAAAAAAAAwQQAAAAAAAExCAAC8QgAAqkIAAKBAAACgQAAAyEEAAHZDAAB2QwAAf0MAAFBDAAAAAAAAEEEAAAAAAAAAAAAAAAAAAAAAAACAQAAAgD8AAAAAAAAAAAAAgD8AAOBAAABwQQAAmEEAAMZCAADOQgAANkMAAD1DAABtQwAAfUMAAHxDAAA/QwAAPkMAAGNDAABzQwAAfEMAAFJDAACQQQAA4EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBAAAAAAAAAAAAAAABCAADaQgAAOUMAAHdDAAB/QwAAckMAAH9DAAB0QwAAf0MAAH9DAAByQwAAe0MAAH9DAABwQwAAf0MAAH9DAABaQwAA+EIAABBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAD+QgAAf0MAAGtDAAB/QwAAf0MAAHdDAABlQwAAVEMAAHJDAAB6QwAAf0MAAH9DAAB4QwAAf0MAAH1DAAB5QwAAf0MAAHNDAAAqQwAAQEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMEEAAAAAAAAQQQAAfUMAAH9DAAB/QwAAaUMAAEpDAACqQgAAAAAAAFRCAABEQwAAbkMAAH9DAABjQwAAbkMAAA5DAADaQgAAQUMAAH9DAABwQwAAf0MAADRDAAAAAAAAAAAAAAAAAAAAAAAAwEAAAAAAAACwQQAAgD8AAHVDAABzQwAAfkMAAH9DAABZQwAAa0MAAGJDAABVQwAAdEMAAHtDAAB/QwAAb0MAAJpCAAAAAAAAAAAAAKBBAAA2QwAAd0MAAG9DAABzQwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIBAAAAlQwAAe0MAAH9DAAB1QwAAf0MAAHJDAAB9QwAAekMAAH9DAABFQwAA1kIAAGxCAAAAAAAAkEEAAABAAADAQAAAAAAAAFhCAAB/QwAAHkMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwEEAAAAAAAAAAAAAwEAAAAhCAAAnQwAAQkMAADBDAAA3QwAAJEMAADBCAAAAQAAAIEEAAMBAAADAQAAAAAAAAAAAAACgQAAAAAAAAIA/AAAAAAAAYEEAAABAAAAAAAAAAAAAAAAAAAAAAAAAIEEAAAAAAABgQQAAAAAAAEBBAAAAAAAAoEAAAAAAAACAPwAAAAAAAMBAAAAAAAAA4EAAAAAAAAAAAAAAAAAAAABBAAAAAAAAIEEAAAAAAACgQAAAAAAAAAAAAAAgQQAAAAAAAAAAAAAAAAAAAAAAAAAAAABgQQAAAAAAAIBAAAAAAAAAAAAAAMhBAAAAAAAAAAAAABBBAAAAAAAAAAAAABBBAAAAAAAAMEEAAAAAAACAPwAAAAAAAAAAAAAAQAAAAAAAAAAAAADgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="}}, "outputFilter": ["Plus214_Output_0"]}
|
|
||||||
@@ -1,228 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
|
|
||||||
"\n",
|
|
||||||
"Licensed under the MIT License."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Register ONNX model and deploy as webservice\n",
|
|
||||||
"\n",
|
|
||||||
"Following this notebook, you will:\n",
|
|
||||||
"\n",
|
|
||||||
" - Learn how to register an ONNX in your Azure Machine Learning Workspace.\n",
|
|
||||||
" - Deploy your model as a web service in an Azure Container Instance."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Prerequisites\n",
|
|
||||||
"\n",
|
|
||||||
"If you are using an Azure Machine Learning Notebook VM, you are all set. Otherwise, make sure you go through the [configuration notebook](../../../configuration.ipynb) to install the Azure Machine Learning Python SDK and create a workspace."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import azureml.core\n",
|
|
||||||
"\n",
|
|
||||||
"# Check core SDK version number.\n",
|
|
||||||
"print('SDK version:', azureml.core.VERSION)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Initialize workspace\n",
|
|
||||||
"\n",
|
|
||||||
"Create a [Workspace](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.workspace%28class%29?view=azure-ml-py) object from your persisted configuration."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"create workspace"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Workspace\n",
|
|
||||||
"\n",
|
|
||||||
"ws = Workspace.from_config()\n",
|
|
||||||
"print(ws.name, ws.resource_group, ws.location, ws.subscription_id, sep='\\n')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Register model\n",
|
|
||||||
"\n",
|
|
||||||
"Register a file or folder as a model by calling [Model.register()](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.model.model?view=azure-ml-py#register-workspace--model-path--model-name--tags-none--properties-none--description-none--datasets-none--model-framework-none--model-framework-version-none--child-paths-none-). For this example, we have provided a trained ONNX MNIST model(`mnist-model.onnx` in the notebook's directory).\n",
|
|
||||||
"\n",
|
|
||||||
"In addition to the content of the model file itself, your registered model will also store model metadata -- model description, tags, and framework information -- that will be useful when managing and deploying models in your workspace. Using tags, for instance, you can categorize your models and apply filters when listing models in your workspace. Also, marking this model with the scikit-learn framework will simplify deploying it as a web service, as we'll see later."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {
|
|
||||||
"tags": [
|
|
||||||
"register model from file"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Model\n",
|
|
||||||
"\n",
|
|
||||||
"model = Model.register(workspace=ws,\n",
|
|
||||||
" model_name='mnist-sample', # Name of the registered model in your workspace.\n",
|
|
||||||
" model_path='mnist-model.onnx', # Local ONNX model to upload and register as a model.\n",
|
|
||||||
" model_framework=Model.Framework.ONNX , # Framework used to create the model.\n",
|
|
||||||
" model_framework_version='1.3', # Version of ONNX used to create the model.\n",
|
|
||||||
" description='Onnx MNIST model')\n",
|
|
||||||
"\n",
|
|
||||||
"print('Name:', model.name)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Deploy model\n",
|
|
||||||
"\n",
|
|
||||||
"Deploy your model as a web service using [Model.deploy()](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.model.model?view=azure-ml-py#deploy-workspace--name--models--inference-config--deployment-config-none--deployment-target-none-). Web services take one or more models, load them in an environment, and run them on one of several supported deployment targets.\n",
|
|
||||||
"\n",
|
|
||||||
"For this example, we will deploy the ONNX model to an Azure Container Instance (ACI)."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Use a default environment (for supported models)\n",
|
|
||||||
"\n",
|
|
||||||
"The Azure Machine Learning service provides a default environment for supported model frameworks, including ONNX, based on the metadata you provided when registering your model. This is the easiest way to deploy your model.\n",
|
|
||||||
"\n",
|
|
||||||
"**Note**: This step can take several minutes."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Webservice\n",
|
|
||||||
"from azureml.exceptions import WebserviceException\n",
|
|
||||||
"\n",
|
|
||||||
"service_name = 'onnx-mnist-service'\n",
|
|
||||||
"\n",
|
|
||||||
"# Remove any existing service under the same name.\n",
|
|
||||||
"try:\n",
|
|
||||||
" Webservice(ws, service_name).delete()\n",
|
|
||||||
"except WebserviceException:\n",
|
|
||||||
" pass\n",
|
|
||||||
"\n",
|
|
||||||
"service = Model.deploy(ws, service_name, [model])\n",
|
|
||||||
"service.wait_for_deployment(show_output=True)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"After your model is deployed, perform a call to the web service."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import requests\n",
|
|
||||||
"\n",
|
|
||||||
"headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}\n",
|
|
||||||
"\n",
|
|
||||||
"if service.auth_enabled:\n",
|
|
||||||
" headers['Authorization'] = 'Bearer '+ service.get_keys()[0]\n",
|
|
||||||
"elif service.token_auth_enabled:\n",
|
|
||||||
" headers['Authorization'] = 'Bearer '+ service.get_token()[0]\n",
|
|
||||||
"\n",
|
|
||||||
"scoring_uri = service.scoring_uri\n",
|
|
||||||
"print(scoring_uri)\n",
|
|
||||||
"with open('onnx-mnist-predict-input.json', 'rb') as data_file:\n",
|
|
||||||
" response = requests.post(\n",
|
|
||||||
" scoring_uri, data=data_file, headers=headers)\n",
|
|
||||||
"print(response.status_code)\n",
|
|
||||||
"print(response.elapsed)\n",
|
|
||||||
"print(response.json())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"When you are finished testing your service, clean up the deployment."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"service.delete()"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "vaidyas"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3.8 - AzureML",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python38-azureml"
|
|
||||||
},
|
|
||||||
"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.7.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
name: onnx-model-register-and-deploy
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
@@ -1,416 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Copyright (c) Microsoft Corporation. All rights reserved. \n",
|
|
||||||
"\n",
|
|
||||||
"Licensed under the MIT License."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
""
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# ResNet50 Image Classification using ONNX and AzureML\n",
|
|
||||||
"\n",
|
|
||||||
"This example shows how to deploy the ResNet50 ONNX model as a web service using Azure Machine Learning services and the ONNX Runtime.\n",
|
|
||||||
"\n",
|
|
||||||
"## What is ONNX\n",
|
|
||||||
"ONNX is an open format for representing machine learning and deep learning models. ONNX enables open and interoperable AI by enabling data scientists and developers to use the tools of their choice without worrying about lock-in and flexibility to deploy to a variety of platforms. ONNX is developed and supported by a community of partners including Microsoft, Facebook, and Amazon. For more information, explore the [ONNX website](http://onnx.ai).\n",
|
|
||||||
"\n",
|
|
||||||
"## ResNet50 Details\n",
|
|
||||||
"ResNet classifies the major object in an input image into a set of 1000 pre-defined classes. For more information about the ResNet50 model and how it was created can be found on the [ONNX Model Zoo github](https://github.com/onnx/models/tree/master/vision/classification/resnet). "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Prerequisites\n",
|
|
||||||
"\n",
|
|
||||||
"To make the best use of your time, make sure you have done the following:\n",
|
|
||||||
"\n",
|
|
||||||
"* Understand the [architecture and terms](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture) introduced by Azure Machine Learning\n",
|
|
||||||
"* If you are using an Azure Machine Learning Notebook VM, you are all set. Otherwise, go through the [configuration notebook](../../../configuration.ipynb) to:\n",
|
|
||||||
" * install the AML SDK\n",
|
|
||||||
" * create a workspace and its configuration file (config.json)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"# Check core SDK version number\n",
|
|
||||||
"import azureml.core\n",
|
|
||||||
"\n",
|
|
||||||
"print(\"SDK version:\", azureml.core.VERSION)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Download pre-trained ONNX model from ONNX Model Zoo.\n",
|
|
||||||
"\n",
|
|
||||||
"Download the [ResNet50v2 model and test data](https://s3.amazonaws.com/onnx-model-zoo/resnet/resnet50v2/resnet50v2.tar.gz) and extract it in the same folder as this tutorial notebook.\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import urllib.request\n",
|
|
||||||
"\n",
|
|
||||||
"onnx_model_url = \"https://s3.amazonaws.com/onnx-model-zoo/resnet/resnet50v2/resnet50v2.tar.gz\"\n",
|
|
||||||
"urllib.request.urlretrieve(onnx_model_url, filename=\"resnet50v2.tar.gz\")\n",
|
|
||||||
"\n",
|
|
||||||
"!tar xvzf resnet50v2.tar.gz"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Deploying as a web service with Azure ML"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Load your Azure ML workspace\n",
|
|
||||||
"\n",
|
|
||||||
"We begin by instantiating a workspace object from the existing workspace created earlier in the configuration notebook."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core import Workspace\n",
|
|
||||||
"\n",
|
|
||||||
"ws = Workspace.from_config()\n",
|
|
||||||
"print(ws.name, ws.location, ws.resource_group, sep = '\\n')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Register your model with Azure ML\n",
|
|
||||||
"\n",
|
|
||||||
"Now we upload the model and register it in the workspace."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import Model\n",
|
|
||||||
"\n",
|
|
||||||
"model = Model.register(model_path = \"resnet50v2/resnet50v2.onnx\",\n",
|
|
||||||
" model_name = \"resnet50v2\",\n",
|
|
||||||
" tags = {\"onnx\": \"demo\"},\n",
|
|
||||||
" description = \"ResNet50v2 from ONNX Model Zoo\",\n",
|
|
||||||
" workspace = ws)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"#### Displaying your registered models\n",
|
|
||||||
"\n",
|
|
||||||
"You can optionally list out all the models that you have registered in this workspace."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"models = ws.models\n",
|
|
||||||
"for name, m in models.items():\n",
|
|
||||||
" print(\"Name:\", name,\"\\tVersion:\", m.version, \"\\tDescription:\", m.description, m.tags)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Write scoring file\n",
|
|
||||||
"\n",
|
|
||||||
"We are now going to deploy our ONNX model on Azure ML using the ONNX Runtime. We begin by writing a score.py file that will be invoked by the web service call. The `init()` function is called once when the container is started so we load the model using the ONNX Runtime into a global session object."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"%%writefile score.py\n",
|
|
||||||
"import json\n",
|
|
||||||
"import time\n",
|
|
||||||
"import sys\n",
|
|
||||||
"import os\n",
|
|
||||||
"import numpy as np # we're going to use numpy to process input and output data\n",
|
|
||||||
"import onnxruntime # to inference ONNX models, we use the ONNX Runtime\n",
|
|
||||||
"\n",
|
|
||||||
"def softmax(x):\n",
|
|
||||||
" x = x.reshape(-1)\n",
|
|
||||||
" e_x = np.exp(x - np.max(x))\n",
|
|
||||||
" return e_x / e_x.sum(axis=0)\n",
|
|
||||||
"\n",
|
|
||||||
"def init():\n",
|
|
||||||
" global session\n",
|
|
||||||
" # AZUREML_MODEL_DIR is an environment variable created during deployment.\n",
|
|
||||||
" # It is the path to the model folder (./azureml-models/$MODEL_NAME/$VERSION)\n",
|
|
||||||
" # For multiple models, it points to the folder containing all deployed models (./azureml-models)\n",
|
|
||||||
" model = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'resnet50v2.onnx')\n",
|
|
||||||
" session = onnxruntime.InferenceSession(model, None)\n",
|
|
||||||
"\n",
|
|
||||||
"def preprocess(input_data_json):\n",
|
|
||||||
" # convert the JSON data into the tensor input\n",
|
|
||||||
" img_data = np.array(json.loads(input_data_json)['data']).astype('float32')\n",
|
|
||||||
" \n",
|
|
||||||
" #normalize\n",
|
|
||||||
" mean_vec = np.array([0.485, 0.456, 0.406])\n",
|
|
||||||
" stddev_vec = np.array([0.229, 0.224, 0.225])\n",
|
|
||||||
" norm_img_data = np.zeros(img_data.shape).astype('float32')\n",
|
|
||||||
" for i in range(img_data.shape[0]):\n",
|
|
||||||
" norm_img_data[i,:,:] = (img_data[i,:,:]/255 - mean_vec[i]) / stddev_vec[i]\n",
|
|
||||||
"\n",
|
|
||||||
" return norm_img_data\n",
|
|
||||||
"\n",
|
|
||||||
"def postprocess(result):\n",
|
|
||||||
" return softmax(np.array(result)).tolist()\n",
|
|
||||||
"\n",
|
|
||||||
"def run(input_data_json):\n",
|
|
||||||
" try:\n",
|
|
||||||
" start = time.time()\n",
|
|
||||||
" # load in our data which is expected as NCHW 224x224 image\n",
|
|
||||||
" input_data = preprocess(input_data_json)\n",
|
|
||||||
" input_name = session.get_inputs()[0].name # get the id of the first input of the model \n",
|
|
||||||
" result = session.run([], {input_name: input_data})\n",
|
|
||||||
" end = time.time() # stop timer\n",
|
|
||||||
" return {\"result\": postprocess(result),\n",
|
|
||||||
" \"time\": end - start}\n",
|
|
||||||
" except Exception as e:\n",
|
|
||||||
" result = str(e)\n",
|
|
||||||
" return {\"error\": result}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Create inference configuration"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"First we create a YAML file that specifies which dependencies we would like to see in our container."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.conda_dependencies import CondaDependencies \n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"myenv = CondaDependencies.create(pip_packages=[\"numpy\", \"onnxruntime\", \"azureml-core\", \"azureml-defaults\"])\n",
|
|
||||||
"\n",
|
|
||||||
"with open(\"myenv.yml\",\"w\") as f:\n",
|
|
||||||
" f.write(myenv.serialize_to_string())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"Create the inference configuration object. Please note that you must indicate azureml-defaults with verion >= 1.0.45 as a pip dependency, because it contains the functionality needed to host the model as a web service."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.model import InferenceConfig\n",
|
|
||||||
"from azureml.core.environment import Environment\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"myenv = Environment.from_conda_specification(name=\"myenv\", file_path=\"myenv.yml\")\n",
|
|
||||||
"inference_config = InferenceConfig(entry_script=\"score.py\", environment=myenv)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"### Deploy the model"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from azureml.core.webservice import AciWebservice\n",
|
|
||||||
"\n",
|
|
||||||
"aciconfig = AciWebservice.deploy_configuration(cpu_cores = 1, \n",
|
|
||||||
" memory_gb = 1, \n",
|
|
||||||
" tags = {'demo': 'onnx'}, \n",
|
|
||||||
" description = 'web service for ResNet50 ONNX model')"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"The following cell will likely take a few minutes to run as well."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"from random import randint\n",
|
|
||||||
"\n",
|
|
||||||
"aci_service_name = 'onnx-demo-resnet50'+str(randint(0,100))\n",
|
|
||||||
"print(\"Service\", aci_service_name)\n",
|
|
||||||
"aci_service = Model.deploy(ws, aci_service_name, [model], inference_config, aciconfig)\n",
|
|
||||||
"aci_service.wait_for_deployment(True)\n",
|
|
||||||
"print(aci_service.state)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"In case the deployment fails, you can check the logs. Make sure to delete your aci_service before trying again."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"if aci_service.state != 'Healthy':\n",
|
|
||||||
" # run this command for debugging.\n",
|
|
||||||
" print(aci_service.get_logs())\n",
|
|
||||||
" aci_service.delete()"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"## Success!\n",
|
|
||||||
"\n",
|
|
||||||
"If you've made it this far, you've deployed a working web service that does image classification using an ONNX model. You can get the URL for the webservice with the code below."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"print(aci_service.scoring_uri)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"When you are eventually done using the web service, remember to delete it."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"aci_service.delete()"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "viswamy"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"category": "deployment",
|
|
||||||
"compute": [
|
|
||||||
"Local"
|
|
||||||
],
|
|
||||||
"datasets": [
|
|
||||||
"ImageNet"
|
|
||||||
],
|
|
||||||
"deployment": [
|
|
||||||
"Azure Container Instance"
|
|
||||||
],
|
|
||||||
"exclude_from_index": false,
|
|
||||||
"framework": [
|
|
||||||
"ONNX"
|
|
||||||
],
|
|
||||||
"friendly_name": "Deploy ResNet50 with ONNX Runtime",
|
|
||||||
"index_order": 4,
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "Python 3.8 - AzureML",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python38-azureml"
|
|
||||||
},
|
|
||||||
"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.6.5"
|
|
||||||
},
|
|
||||||
"star_tag": [],
|
|
||||||
"tags": [
|
|
||||||
"ONNX Model Zoo"
|
|
||||||
],
|
|
||||||
"task": "Image Classification"
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
name: onnx-modelzoo-aml-deploy-resnet50
|
|
||||||
dependencies:
|
|
||||||
- pip:
|
|
||||||
- azureml-sdk
|
|
||||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user