Compare commits

...

21 Commits

Author SHA1 Message Date
Jeff Shepherd
113543dfbf Fixed continuous retraining notebook 2024-02-14 14:53:33 -08:00
Jeff Shepherd
f0d7379af7 Updated curated environments in sample notebooks 2024-02-13 11:47:56 -08:00
jeff-shepherd
33ca8c7933 Merge pull request #1957 from Azure/release_update_stablev2/Release-207
update samples from Release-207 as a part of 1.55.0 SDK stable release
2024-02-07 08:48:02 -08:00
amlrelsa-ms
3fd1ce8993 update samples from Release-207 as a part of 1.55.0 SDK stable release 2024-02-06 19:58:35 +00:00
jeff-shepherd
aa93588190 Merge pull request #1954 from Azure/jeffshep/pinpy38
Temporarily pin back to Python 3.8
2023-12-07 11:03:20 -08:00
Jeff Shepherd
12520400e5 Temporarily pin back to Python 3.8 2023-12-06 13:24:28 -08:00
jeff-shepherd
35614e83fa Merge pull request #1951 from Azure/release_update_stablev2/Release-200
update samples from Release-200 as a part of 1.54.0 SDK stable release
2023-11-22 18:24:05 -08:00
amlrelsa-ms
ff22ac01cc update samples from Release-200 as a part of 1.54.0 SDK stable release 2023-11-21 17:51:12 +00:00
jeff-shepherd
e7dd826f34 Merge pull request #1946 from Azure/jeffshep/pinscikit-learn
Pin scikit-learn to avoid conflict with azureml-responsibleai
2023-10-23 14:57:13 -07:00
Jeff Shepherd
fcc882174b Pin scikit-learn to avoid conflict with azureml-responsibleai 2023-10-23 09:53:39 -07:00
jeff-shepherd
6872d8a3bb Merge pull request #1941 from Azure/jeffshep/updatefor1.53.2
Updated automl_env.yml for Azure ML SDK 1.53.2
2023-10-10 08:49:04 -07:00
Jeff Shepherd
a2cb4c3589 Updated fbprophet to prophet 2023-10-10 08:47:09 -07:00
Jeff Shepherd
15008962b2 Updated automl_env.yml for Azure ML SDK 1.53.2 2023-10-05 19:29:26 -07:00
jeff-shepherd
9414b51fac Merge pull request #1937 from Azure/jeffshep/fixwindows153
Fixed Windows automl_setup for 1.53.0
2023-08-31 21:56:12 -07:00
Jeff Shepherd
80ac414582 Fixed Windows automl_setup for 1.53.0 2023-08-31 16:54:20 -07:00
jeff-shepherd
cbc151660b Merge pull request #1936 from Azure/jeffshep/fixtabulardataset
Fixed tabular-dataset-partition-per-column.ipynb
2023-08-25 15:34:08 -07:00
Jeff Shepherd
0024abc6e3 Fixed tabular-dataset-partition-per-column.ipynb and removed deploy-to-cloud/model-register-and-deploy.ipynb 2023-08-25 13:52:29 -07:00
jeff-shepherd
fa13385860 Merge pull request #1935 from Azure/release_update_stablev2/Release-193
update samples from Release-193 as a part of 1.53.0 SDK stable release
2023-08-23 11:41:24 -07:00
Jeff Shepherd
0c5f6daf52 Fixed readme syntax 2023-08-23 11:37:30 -07:00
Jeff Shepherd
c11e9fc1da Fixed readme syntax 2023-08-23 11:36:17 -07:00
Jeff Shepherd
280150713e Restored V2 message 2023-08-23 10:20:25 -07:00
54 changed files with 1698 additions and 4660 deletions

View File

@@ -1,6 +1,6 @@
# 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!

View File

@@ -103,7 +103,7 @@
"source": [
"import azureml.core\n",
"\n",
"print(\"This notebook was created using version 1.53.0 of the Azure ML SDK\")\n",
"print(\"This notebook was created using version 1.55.0 of the Azure ML SDK\")\n",
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
]
},

View File

@@ -6,7 +6,7 @@ dependencies:
- fairlearn>=0.6.2,<=0.7.0
- joblib
- liac-arff
- raiwidgets~=0.28.0
- raiwidgets~=0.33.0
- itsdangerous==2.0.1
- markupsafe<2.1.0
- protobuf==3.20.0

View File

@@ -6,7 +6,7 @@ dependencies:
- fairlearn>=0.6.2,<=0.7.0
- joblib
- liac-arff
- raiwidgets~=0.28.0
- raiwidgets~=0.33.0
- itsdangerous==2.0.1
- markupsafe<2.1.0
- protobuf==3.20.0

View File

@@ -5,22 +5,21 @@ channels:
- main
dependencies:
# 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
- python>=3.8,<3.9
- holidays==0.10.3
- conda-forge::fbprophet==0.7.1
- pandas==1.1.5
- scipy==1.5.3
- Cython==0.29.14
- tqdm==4.65.0
- python>=3.9,<3.10
- holidays==0.29
- scipy==1.10.1
- tqdm==4.66.1
- pip:
# Required packages for AzureML execution, history, and data preparation.
- azureml-widgets~=1.53.0
- azureml-defaults~=1.53.0
- -r https://automlsdkdataresources.blob.core.windows.net/validated-requirements/1.53.0/validated_win32_requirements.txt [--no-deps]
- azureml-widgets~=1.55.0
- azureml-defaults~=1.55.0
- -r https://automlsdkdataresources.blob.core.windows.net/validated-requirements/1.55.0/validated_win32_requirements.txt [--no-deps]
- matplotlib==3.7.1
- xgboost==1.3.3
- cmdstanpy==0.9.5
- prophet==1.1.4
- pandas==1.3.5
- cmdstanpy==1.1.0
- setuptools-git==1.2

View File

@@ -7,26 +7,24 @@ dependencies:
# The python interpreter version.
# Azure ML only supports 3.7 and later.
- pip==22.3.1
- python>=3.8,<3.9
- python>=3.9,<3.10
- matplotlib==3.7.1
- numpy>=1.21.6,<=1.22.3
- cython==0.29.14
- numpy>=1.21.6,<=1.23.5
- urllib3==1.26.7
- scipy>=1.4.1,<=1.5.3
- scikit-learn==1.1.0
- scipy==1.10.1
- scikit-learn=1.1.3
- py-xgboost<=1.3.3
- holidays==0.10.3
- conda-forge::fbprophet==0.7.1
- holidays==0.29
- pytorch::pytorch=1.11.0
- cudatoolkit=10.1.243
- notebook
- pip:
# Required packages for AzureML execution, history, and data preparation.
- azureml-widgets~=1.53.0
- azureml-defaults~=1.53.0
- azureml-widgets~=1.55.0
- azureml-defaults~=1.55.0
- pytorch-transformers==1.0.0
- spacy==2.2.4
- pystan==2.19.1.1
- https://aka.ms/automl-resources/packages/en_core_web_sm-2.1.0.tar.gz
- -r https://automlsdkdataresources.blob.core.windows.net/validated-requirements/1.53.0/validated_linux_requirements.txt [--no-deps]
- spacy==2.3.9
- prophet==1.1.4
- https://aka.ms/automl-resources/packages/en_core_web_sm-2.3.1.tar.gz
- -r https://automlsdkdataresources.blob.core.windows.net/validated-requirements/1.55.0/validated_linux_requirements.txt [--no-deps]

View File

@@ -7,22 +7,20 @@ dependencies:
# The python interpreter version.
# Currently Azure ML only supports 3.7 and later.
- pip==22.3.1
- python>=3.8,<3.9
- numpy>=1.21.6,<=1.22.3
- cython==0.29.14
- scipy>=1.4.1,<=1.5.3
- scikit-learn==1.1.0
- holidays==0.10.3
- python>=3.9,<3.10
- numpy>=1.21.6,<=1.23.5
- scipy==1.10.1
- scikit-learn==1.1.3
- holidays==0.29
- pip:
# Required packages for AzureML execution, history, and data preparation.
- azureml-widgets~=1.53.0
- azureml-defaults~=1.53.0
- azureml-widgets~=1.55.0
- azureml-defaults~=1.55.0
- pytorch-transformers==1.0.0
- spacy==2.2.4
- pystan==2.19.1.1
- fbprophet==0.7.1
- prophet==1.1.4
- xgboost==1.3.3
- spacy==2.3.9
- matplotlib==3.7.1
- https://aka.ms/automl-resources/packages/en_core_web_sm-2.1.0.tar.gz
- -r https://automlsdkdataresources.blob.core.windows.net/validated-requirements/1.53.0/validated_darwin_requirements.txt [--no-deps]
- https://aka.ms/automl-resources/packages/en_core_web_sm-2.3.1.tar.gz
- -r https://automlsdkdataresources.blob.core.windows.net/validated-requirements/1.55.0/validated_darwin_requirements.txt [--no-deps]

View File

@@ -1,609 +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": [
"![Impressions](https://PixelServer20190423114238.azurewebsites.net/api/impressions/MachineLearningNotebooks/how-to-use-azureml/automated-machine-learning/classification-text-dnn/auto-ml-classification-text-dnn.png)"
]
},
{
"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_NC6s_v3\", # CPU for BiLSTM, such as \"STANDARD_D2_V2\"\n",
" # To use BERT (this is recommended for best performance), select a GPU such as \"Standard_NC6s_v3\"\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 MachineLearningNotebooks folder here: \"MachineLearningNotebooks\\how-to-use-azureml\\automated-machine-learning\""
]
},
{
"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
}

View File

@@ -1,4 +0,0 @@
name: auto-ml-classification-text-dnn
dependencies:
- pip:
- azureml-sdk

View File

@@ -1,80 +0,0 @@
import json
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,
):
try:
inference_env = train_run.get_environment()
except BaseException:
run_details = train_run.get_details()
run_def = run_details.get("runDefinition")
env = run_def.get("environment")
if env is None:
raise
json.dump(env, open("azureml_environment.json", "w"))
inference_env = Environment.load_from_directory(".")
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

View File

@@ -1,70 +0,0 @@
import argparse
import pandas as pd
import numpy as np
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)

View File

@@ -36,7 +36,10 @@ except Exception:
last_train_time = datetime.min.replace(tzinfo=pytz.UTC)
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:
print("Cancelling run since there is no new data.")

View File

@@ -97,7 +97,7 @@
"metadata": {},
"outputs": [],
"source": [
"print(\"This notebook was created using version 1.53.0 of the Azure ML SDK\")\n",
"print(\"This notebook was created using version 1.55.0 of the Azure ML SDK\")\n",
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
]
},

View File

@@ -97,7 +97,7 @@
"metadata": {},
"outputs": [],
"source": [
"print(\"This notebook was created using version 1.53.0 of the Azure ML SDK\")\n",
"print(\"This notebook was created using version 1.55.0 of the Azure ML SDK\")\n",
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
]
},

View File

@@ -92,7 +92,7 @@
"metadata": {},
"outputs": [],
"source": [
"print(\"This notebook was created using version 1.53.0 of the Azure ML SDK\")\n",
"print(\"This notebook was created using version 1.55.0 of the Azure ML SDK\")\n",
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
]
},

View File

@@ -91,7 +91,7 @@
"metadata": {},
"outputs": [],
"source": [
"print(\"This notebook was created using version 1.53.0 of the Azure ML SDK\")\n",
"print(\"This notebook was created using version 1.55.0 of the Azure ML SDK\")\n",
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
]
},

View File

@@ -1,5 +1,21 @@
{
"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": [
"![Impressions](https://PixelServer20190423114238.azurewebsites.net/api/impressions/MachineLearningNotebooks/how-to-use-azureml/automated-machine-learning/forecasting-pipelines/auto-ml-forecasting-pipelines.png)"
]
},
{
"cell_type": "markdown",
"metadata": {},
@@ -55,7 +71,6 @@
"import logging\n",
"import os\n",
"\n",
"from matplotlib import pyplot as plt\n",
"import pandas as pd\n",
"\n",
"import azureml.core\n",
@@ -441,8 +456,6 @@
"metadata": {},
"outputs": [],
"source": [
"from azureml.pipeline.core import PipelineData\n",
"\n",
"# The model name with which to register the trained model in the workspace.\n",
"model_name_str = \"ojmodel\"\n",
"model_name = PipelineParameter(\"model_name\", default_value=model_name_str)\n",

View File

@@ -1,5 +1,21 @@
{
"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": [
"![Impressions](https://PixelServer20190423114238.azurewebsites.net/api/impressions/MachineLearningNotebooks/how-to-use-azureml/automated-machine-learning/local-run-classification-credit-card-fraud/auto-ml-classification-credit-card-fraud-local.png)"
]
},
{
"cell_type": "markdown",
"metadata": {},

View File

@@ -1,5 +1,21 @@
{
"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": [
"![Impressions](https://PixelServer20190423114238.azurewebsites.net/api/impressions/MachineLearningNotebooks/how-to-use-azureml/automated-machine-learning/regression/auto-ml-regression.png)"
]
},
{
"cell_type": "markdown",
"metadata": {},

View File

@@ -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).

View File

@@ -1,599 +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": [
"![Impressions](https://PixelServer20190423114238.azurewebsites.net/api/impressions/MachineLearningNotebooks/how-to-use-azureml/deployment/deploy-to-cloud/model-register-and-deploy.png)"
]
},
{
"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 dill\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",
"dill.dump(model, open('sklearn_regression_model.pkl', 'wb'))"
]
},
{
"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",
" 'dill==0.3.6',\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",
" 'dill==0.3.6',\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 [&ldquo;How and where to deploy models&rdquo;](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
}

View File

@@ -1,6 +0,0 @@
name: model-register-and-deploy
dependencies:
- pip:
- azureml-sdk
- numpy
- scikit-learn

View File

@@ -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()

View File

@@ -94,15 +94,15 @@ def main():
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
# MNIST dataset
datasets.MNIST.resources = [
("https://azureopendatastorage.azurefd.net/mnist/train-images-idx3-ubyte.gz",
("train-images-idx3-ubyte.gz",
"f68b3c2dcbeaaa9fbdd348bbdeb94873"),
("https://azureopendatastorage.azurefd.net/mnist/train-labels-idx1-ubyte.gz",
("train-labels-idx1-ubyte.gz",
"d53e105ee54ea40749a09fcbcd1e9432"),
("https://azureopendatastorage.azurefd.net/mnist/t10k-images-idx3-ubyte.gz",
("t10k-images-idx3-ubyte.gz",
"9fb629c4189551a2d022fa330f9573f3"),
("https://azureopendatastorage.azurefd.net/mnist/t10k-labels-idx1-ubyte.gz",
("t10k-labels-idx1-ubyte.gz",
"ec29112dd5afa0611ce80d1b7f02629c")
]
train_loader = torch.utils.data.DataLoader(

View File

@@ -260,7 +260,7 @@
"source": [
"from azureml.core.conda_dependencies import CondaDependencies \n",
"\n",
"myenv = CondaDependencies.create(pip_packages=[\"numpy\", \"onnxruntime\", \"azureml-core\", \"azureml-defaults\"])\n",
"myenv = CondaDependencies.create(pip_packages=[\"numpy\", \"onnxruntime==1.15.1\", \"azureml-core\", \"azureml-defaults\"])\n",
"\n",
"with open(\"myenv.yml\",\"w\") as f:\n",
" f.write(myenv.serialize_to_string())"

View File

@@ -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": [
"![Impressions](https://PixelServer20190423114238.azurewebsites.net/api/impressions/MachineLearningNotebooks/how-to-use-azureml/deployment/onnx/onnx-inference-facial-expression-recognition-deploy.png)"
]
},
{
"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",
"![](https://raw.githubusercontent.com/Microsoft/FERPlus/master/FER+vsFER.png)\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": [
"![](https://raw.githubusercontent.com/vinitra/FERPlus/master/emotion_model_img.png)"
]
},
{
"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
}

View File

@@ -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

View File

@@ -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": [
"![Impressions](https://PixelServer20190423114238.azurewebsites.net/api/impressions/MachineLearningNotebooks/how-to-use-azureml/deployment/onnx/onnx-inference-mnist-deploy.png)"
]
},
{
"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
}

View File

@@ -1,9 +0,0 @@
name: onnx-inference-mnist-deploy
dependencies:
- pip:
- azureml-sdk
- azureml-widgets
- matplotlib
- numpy
- onnx<1.7.0
- opencv-python-headless

View File

@@ -242,7 +242,7 @@
"from azureml.core.conda_dependencies import CondaDependencies \n",
"\n",
"\n",
"myenv = CondaDependencies.create(pip_packages=[\"numpy\", \"onnxruntime\", \"azureml-core\", \"azureml-defaults\"])\n",
"myenv = CondaDependencies.create(pip_packages=[\"numpy\", \"onnxruntime==1.15.1\", \"azureml-core\", \"azureml-defaults\"])\n",
"\n",
"with open(\"myenv.yml\",\"w\") as f:\n",
" f.write(myenv.serialize_to_string())"

File diff suppressed because one or more lines are too long

View File

@@ -270,6 +270,7 @@
"sklearn_ver = None\n",
"pandas_ver = None\n",
"joblib_ver = None\n",
"scipy_ver = None\n",
"for dist in list(available_packages):\n",
" if dist.key == 'scikit-learn':\n",
" sklearn_ver = dist.version\n",
@@ -277,21 +278,26 @@
" pandas_ver = dist.version\n",
" elif dist.key == 'joblib':\n",
" joblib_ver = dist.version\n",
" elif dist.key == 'scipy':\n",
" scipy_ver = dist.version\n",
"sklearn_dep = 'scikit-learn'\n",
"pandas_dep = 'pandas'\n",
"joblib_dep = 'joblib'\n",
"scipy_dep = 'scipy'\n",
"if sklearn_ver:\n",
" sklearn_dep = 'scikit-learn=={}'.format(sklearn_ver)\n",
"if pandas_ver:\n",
" pandas_dep = 'pandas=={}'.format(pandas_ver)\n",
"if joblib_ver:\n",
" joblib_dep = 'joblib=={}'.format(joblib_ver)\n",
"if scipy_ver:\n",
" scipy_dep = 'scipy=={}'.format(scipy_ver)\n",
"# Specify CondaDependencies obj\n",
"# The CondaDependencies specifies the conda and pip packages that are installed in the environment\n",
"# the submitted job is run in. Note the remote environment(s) needs to be similar to the local\n",
"# environment, otherwise if a model is trained or deployed in a different environment this can\n",
"# cause errors. Please take extra care when specifying your dependencies in a production environment.\n",
"azureml_pip_packages.extend([sklearn_dep, pandas_dep, joblib_dep])\n",
"azureml_pip_packages.extend([sklearn_dep, pandas_dep, joblib_dep, scipy_dep])\n",
"run_config.environment.python.conda_dependencies = CondaDependencies.create(pip_packages=azureml_pip_packages, python_version=python_version)\n",
"\n",
"from azureml.core import ScriptRunConfig\n",

View File

@@ -9,7 +9,7 @@ dependencies:
- ipython
- matplotlib
- ipywidgets
- raiwidgets~=0.28.0
- raiwidgets~=0.33.0
- itsdangerous==2.0.1
- markupsafe<2.1.0
- scipy>=1.5.3

View File

@@ -9,7 +9,7 @@ dependencies:
- ipython
- matplotlib
- ipywidgets
- raiwidgets~=0.28.0
- raiwidgets~=0.33.0
- packaging>=20.9
- itsdangerous==2.0.1
- markupsafe<2.1.0

View File

@@ -9,7 +9,7 @@ dependencies:
- ipython
- matplotlib
- ipywidgets
- raiwidgets~=0.28.0
- raiwidgets~=0.33.0
- packaging>=20.9
- itsdangerous==2.0.1
- markupsafe<2.1.0

View File

@@ -10,7 +10,7 @@ dependencies:
- matplotlib
- azureml-core
- ipywidgets
- raiwidgets~=0.28.0
- raiwidgets~=0.33.0
- itsdangerous==2.0.1
- markupsafe<2.1.0
- scipy>=1.5.3

View File

@@ -68,7 +68,13 @@
"from datetime import datetime\n",
"from dateutil.relativedelta import relativedelta\n",
"\n",
"green_df_raw = pd.DataFrame([])\n",
"green_df_raw = pd.DataFrame([\n",
" [2,\"2016-01-03 21:02:35\",\"2016-01-03 21:05:52\",1,0.83,\"\",\"\",-73.98726654052734,40.6938362121582,-73.97611236572266,40.69454574584961,1,\"N\",1,4.5,0.5,0.5,0.3,0.0,0.0,\"\",5.8,1.0],\n",
" [2,\"2016-01-19 21:49:17\",\"2016-01-19 21:54:37\",2,1.27,\"\",\"\",-73.94845581054688,40.80146789550781,-73.95975494384766,40.81214904785156,1,\"N\",1,6.0,0.5,0.5,0.3,1.0,0.0,\"\",8.3,1.0],\n",
" [2,\"2016-01-05 09:46:18\",\"2016-01-05 09:57:28\",1,1.8,\"\",\"\",-73.9554443359375,40.6797981262207,-73.98030853271484,40.678741455078125,1,\"N\",1,9.5,0.0,0.5,0.3,2.06,0.0,\"\",12.36,1.0],\n",
" [1,\"2016-01-08 17:49:12\",\"2016-01-08 17:52:20\",1,0.5,\"\",\"\",-73.92293548583984,40.76081848144531,-73.92549896240234,40.75471496582031,1,\"N\",1,4.0,1.0,0.5,0.3,1.15,0.0,\"\",6.95,1.0],\n",
" [1,\"2016-01-29 10:28:21\",\"2016-01-29 10:34:59\",1,0.9,\"\",\"\",-73.92304229736328,40.664939880371094,-73.91104125976562,40.66966247558594,1,\"N\",2,6.0,0.0,0.5,0.3,0.0,0.0,\"\",6.8,1.0],\n",
" ] * 50, columns=[\"vendorID\",\"lpepPickupDatetime\",\"lpepDropoffDatetime\",\"passengerCount\",\"tripDistance\",\"puLocationId\",\"doLocationId\",\"pickupLongitude\",\"pickupLatitude\",\"dropoffLongitude\",\"dropoffLatitude\",\"rateCodeID\",\"storeAndFwdFlag\",\"paymentType\",\"fareAmount\",\"extra\",\"mtaTax\",\"improvementSurcharge\",\"tipAmount\",\"tollsAmount\",\"ehailFee\",\"totalAmount\",\"tripType\"])\n",
"start = datetime.strptime(\"1/1/2016\",\"%m/%d/%Y\")\n",
"end = datetime.strptime(\"1/31/2016\",\"%m/%d/%Y\")\n",
"\n",
@@ -78,6 +84,8 @@
"for sample_month in range(number_of_months):\n",
" temp_df_green = NycTlcGreen(start + relativedelta(months=sample_month), end + relativedelta(months=sample_month)) \\\n",
" .to_pandas_dataframe()\n",
" if temp_df_green is None:\n",
" continue\n",
" green_df_raw = green_df_raw.append(temp_df_green.sample(sample_size))"
]
},
@@ -87,7 +95,13 @@
"metadata": {},
"outputs": [],
"source": [
"yellow_df_raw = pd.DataFrame([])\n",
"yellow_df_raw = pd.DataFrame([\n",
" [2,\"2016-01-06 12:09:13\",\"2016-01-06 12:22:14\",1,2.09,\"\",\"\",-73.98207092285156,40.74605941772461,-74.00462341308594,40.730628967285156,1,\"N\",1,10.5,0.0,0.5,0.3,2.26,0.0,13.56],\n",
" [1,\"2016-01-03 17:57:48\",\"2016-01-03 18:08:18\",3,1.5,\"\",\"\",-73.96627044677734,40.764835357666016,-73.98455047607422,40.75786209106445,1,\"N\",2,8.5,1.0,0.5,0.3,0.0,0.0,10.3],\n",
" [1,\"2016-01-18 07:37:51\",\"2016-01-18 07:47:01\",1,1.8,\"\",\"\",0.0,0.0,0.0,0.0,1,\"N\",1,8.5,0.0,0.5,0.3,1.85,0.0,11.15],\n",
" [2,\"2016-01-26 00:31:36\",\"2016-01-26 00:38:47\",1,1.96,\"\",\"\",-73.9906234741211,40.7553596496582,-73.97895812988281,40.78070831298828,1,\"N\",1,8.0,0.5,0.5,0.3,1.0,0.0,10.3],\n",
" [2,\"2016-01-20 23:37:22\",\"2016-01-20 23:51:09\",1,3.6,\"\",\"\",-73.98528289794922,40.76026153564453,-74.01127624511719,40.7148323059082,1,\"N\",1,13.5,0.5,0.5,0.3,2.5,0.0,17.3]\n",
" ] * 50, columns=[\"vendorID\",\"tpepPickupDateTime\",\"tpepDropoffDateTime\",\"passengerCount\",\"tripDistance\",\"puLocationId\",\"doLocationId\",\"startLon\",\"startLat\",\"endLon\",\"endLat\",\"rateCodeID\",\"storeAndFwdFlag\",\"paymentType\",\"fareAmount\",\"extra\",\"mtaTax\",\"improvementSurcharge\",\"tipAmount\",\"tollsAmount\",\"totalAmount\"])\n",
"start = datetime.strptime(\"1/1/2016\",\"%m/%d/%Y\")\n",
"end = datetime.strptime(\"1/31/2016\",\"%m/%d/%Y\")\n",
"\n",
@@ -96,6 +110,8 @@
"for sample_month in range(number_of_months):\n",
" temp_df_yellow = NycTlcYellow(start + relativedelta(months=sample_month), end + relativedelta(months=sample_month)) \\\n",
" .to_pandas_dataframe()\n",
" if temp_df_yellow is None:\n",
" continue\n",
" yellow_df_raw = yellow_df_raw.append(temp_df_yellow.sample(sample_size))"
]
},
@@ -286,7 +302,7 @@
"# Specify CondaDependencies obj, add necessary packages\n",
"aml_run_config.environment.python.conda_dependencies = CondaDependencies.create(\n",
" conda_packages=['pandas','scikit-learn'], \n",
" pip_packages=['azureml-sdk[automl]', 'pyarrow'])\n",
" pip_packages=['azureml-sdk[automl]', 'pyarrow==14.0.2'])\n",
"\n",
"print (\"Run configuration created.\")"
]
@@ -554,7 +570,6 @@
"Transform the normalized taxi data to final required format. This steps does the following:\n",
"\n",
"- Split the pickup and dropoff date further into the day of the week, day of the month, and month values. \n",
"- To get the day of the week value, uses the derive_column_by_example() function. The function takes an array parameter of example objects that define the input data, and the preferred output. The function automatically determines the preferred transformation. For the pickup and dropoff time columns, split the time into the hour, minute, and second by using the split_column_by_example() function with no example parameter.\n",
"- After new features are generated, use the drop_columns() function to delete the original fields as the newly generated features are preferred. \n",
"- Rename the rest of the fields to use meaningful descriptions."
]

View File

@@ -21,11 +21,9 @@ print("Argument 2(output final transformed taxi data): %s" % args.output_transfo
# These functions transform the renamed data to be used finally for training.
# Split the pickup and dropoff date further into the day of the week, day of the month, and month values.
# To get the day of the week value, use the derive_column_by_example() function.
# The function takes an array parameter of example objects that define the input data,
# and the preferred output. The function automatically determines your preferred transformation.
# For the pickup and dropoff time columns, split the time into the hour, minute, and second by using
# the split_column_by_example() function with no example parameter. After you generate the new features,
# use the drop_columns() function to delete the original fields as the newly generated features are preferred.
# Rename the rest of the fields to use meaningful descriptions.

View File

@@ -12,13 +12,16 @@ from azureml.core import Model
def init():
global g_tf_sess
# Disable eager execution
tf.compat.v1.disable_eager_execution()
# pull down model from workspace
model_path = Model.get_model_path("mnist-prs")
# contruct graph to execute
tf.reset_default_graph()
saver = tf.train.import_meta_graph(os.path.join(model_path, 'mnist-tf.model.meta'))
g_tf_sess = tf.Session(config=tf.ConfigProto(device_count={'GPU': 0}))
tf.compat.v1.reset_default_graph()
saver = tf.compat.v1.train.import_meta_graph(os.path.join(model_path, 'mnist-tf.model.meta'))
g_tf_sess = tf.compat.v1.Session(config=tf.compat.v1.ConfigProto(device_count={'GPU': 0}))
saver.restore(g_tf_sess, os.path.join(model_path, 'mnist-tf.model'))
@@ -33,7 +36,7 @@ def run(mini_batch):
data = Image.open(image)
np_im = np.array(data).reshape((1, 784))
# perform inference
inference_result = output.eval(feed_dict={in_tensor: np_im}, session=g_tf_sess)
inference_result = g_tf_sess.run(output, feed_dict={in_tensor: np_im})
# find best probability, and add to result list
best_result = np.argmax(inference_result)
resultList.append("{}: {}".format(os.path.basename(image), best_result))

View File

@@ -1,10 +1,7 @@
import io
import pickle
import argparse
import numpy as np
from azureml.core.model import Model
from sklearn.linear_model import LogisticRegression
from azureml_user.parallel_run import EntryScript

View File

@@ -306,7 +306,7 @@
"#### An entry script\n",
"This script accepts requests, scores the requests by using the model, and returns the results.\n",
"- __init()__ - Typically this function loads the model into a global object. This function is run only once at the start of batch processing per worker node/process. Init method can make use of following environment variables (ParallelRunStep input):\n",
" 1.\tAZUREML_BI_OUTPUT_PATH \u00e2\u20ac\u201c output folder path\n",
" 1.\tAZUREML_BI_OUTPUT_PATH - output folder path\n",
"- __run(mini_batch)__ - The method to be parallelized. Each invocation will have one minibatch.<BR>\n",
"__mini_batch__: Batch inference will invoke run method and pass either a list or Pandas DataFrame as an argument to the method. Each entry in min_batch will be - a filepath if input is a FileDataset, a Pandas DataFrame if input is a TabularDataset.<BR>\n",
"__run__ method response: run() method should return a Pandas DataFrame or an array. For append_row output_action, these returned elements are appended into the common output file. For summary_only, the contents of the elements are ignored. For all output actions, each returned output element indicates one successful inference of input element in the input mini-batch.\n",
@@ -359,9 +359,9 @@
"from azureml.core import Environment\n",
"from azureml.core.runconfig import CondaDependencies, DEFAULT_CPU_IMAGE\n",
"\n",
"batch_conda_deps = CondaDependencies.create(python_version=\"3.7\",\n",
"batch_conda_deps = CondaDependencies.create(python_version=\"3.8\",\n",
" conda_packages=['pip==20.2.4'],\n",
" pip_packages=[\"tensorflow==1.15.2\", \"pillow\", \"protobuf==3.20.1\",\n",
" pip_packages=[\"tensorflow==2.13.0\", \"pillow\", \"protobuf==4.23.3\",\n",
" \"azureml-core\", \"azureml-dataset-runtime[fuse]\"])\n",
"batch_env = Environment(name=\"batch_environment\")\n",
"batch_env.python.conda_dependencies = batch_conda_deps\n",
@@ -615,7 +615,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.9"
"version": "3.8.16"
},
"tags": [
"Batch Inferencing",

View File

@@ -390,7 +390,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.9"
"version": "3.8.16"
}
},
"nbformat": 4,

View File

@@ -252,7 +252,7 @@
"#### An entry script\n",
"This script accepts requests, scores the requests by using the model, and returns the results.\n",
"- __init()__ - Typically this function loads the model into a global object. This function is run only once at the start of batch processing per worker node/process. init method can make use of following environment variables (ParallelRunStep input):\n",
" 1.\tAZUREML_BI_OUTPUT_PATH \u00e2\u20ac\u201c output folder path\n",
" 1.\tAZUREML_BI_OUTPUT_PATH - output folder path\n",
"- __run(mini_batch)__ - The method to be parallelized. Each invocation will have one minibatch.<BR>\n",
"__mini_batch__: Batch inference will invoke run method and pass either a list or Pandas DataFrame as an argument to the method. Each entry in min_batch will be - a filepath if input is a FileDataset, a Pandas DataFrame if input is a TabularDataset.<BR>\n",
"__run__ method response: run() method should return a Pandas DataFrame or an array. For append_row output_action, these returned elements are appended into the common output file. For summary_only, the contents of the elements are ignored. For all output actions, each returned output element indicates one successful inference of input element in the input mini-batch.\n",
@@ -308,10 +308,11 @@
"from azureml.core import Environment\n",
"from azureml.core.runconfig import CondaDependencies\n",
"\n",
"predict_conda_deps = CondaDependencies.create(python_version=\"3.7\", \n",
"predict_conda_deps = CondaDependencies.create(python_version=\"3.8\", \n",
" conda_packages=['pip==20.2.4'],\n",
" pip_packages=[\"scikit-learn==0.20.3\",\n",
" \"azureml-core\", \"azureml-dataset-runtime[pandas,fuse]\"])\n",
" pin_sdk_version=False,\n",
" pip_packages=[\"numpy==1.19.5\", \"pandas==1.4.4\", \"scikit-learn==0.22.2\",\n",
" \"azureml-core==1.54.0\", \"azureml-dataset-runtime[fuse]==1.54.0\"])\n",
"\n",
"predict_env = Environment(name=\"predict_environment\")\n",
"predict_env.python.conda_dependencies = predict_conda_deps\n",
@@ -521,7 +522,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.2"
"version": "3.8.16"
},
"tags": [
"Batch Inferencing",

View File

@@ -86,8 +86,7 @@
"import requests\n",
"\n",
"oj_sales_path = \"./oj.csv\"\n",
"r = requests.get(\"https://raw.githubusercontent.com/Azure/MachineLearningNotebooks/master/how-to-use-azureml/\n",
" automated-machine-learning/automl-forecasting-orange-juice-sales/data/dominicks_OJ.csv\")\n",
"r = requests.get(\"https://raw.githubusercontent.com/Azure/azureml-examples/main/sdk/python/jobs/automl-standalone-jobs/automl-forecasting-orange-juice-sales/data/dominicks_OJ.csv\")\n",
"open(oj_sales_path, \"wb\").write(r.content)"
]
},
@@ -414,7 +413,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.13"
"version": "3.8.16"
}
},
"nbformat": 4,

View File

@@ -308,7 +308,7 @@
"metadata": {},
"outputs": [],
"source": [
"cd = CondaDependencies.create(python_version=\"3.7\", conda_packages=['pip==20.2.4'])\n",
"cd = CondaDependencies.create(python_version=\"3.8\", conda_packages=['pip==20.2.4'])\n",
"\n",
"cd.add_channel(\"conda-forge\")\n",
"cd.add_conda_package(\"ffmpeg==4.0.2\")\n",
@@ -401,7 +401,7 @@
"from azureml.core import Environment\n",
"from azureml.core.runconfig import DEFAULT_GPU_IMAGE\n",
"\n",
"parallel_cd = CondaDependencies.create(python_version=\"3.7\", conda_packages=['pip==20.2.4', 'numpy==1.19'])\n",
"parallel_cd = CondaDependencies.create(python_version=\"3.8\", conda_packages=['pip==20.2.4', 'numpy==1.19'])\n",
"\n",
"parallel_cd.add_channel(\"pytorch\")\n",
"parallel_cd.add_conda_package(\"pytorch\")\n",

View File

@@ -282,7 +282,7 @@
"source": [
"### Create an environment\n",
"\n",
"In this tutorial, we will use one of Azure ML's curated PyTorch environments for training. [Curated environments](https://docs.microsoft.com/azure/machine-learning/how-to-use-environments#use-a-curated-environment) are available in your workspace by default. Specifically, we will use the PyTorch 1.6 GPU curated environment."
"In this tutorial, we will use one of Azure ML's curated PyTorch environments for training. [Curated environments](https://docs.microsoft.com/azure/machine-learning/how-to-use-environments#use-a-curated-environment) are available in your workspace by default. Specifically, we will use the PyTorch 2.0 GPU curated environment."
]
},
{
@@ -293,7 +293,7 @@
"source": [
"from azureml.core import Environment\n",
"\n",
"pytorch_env = Environment.get(ws, name='azureml-acpt-pytorch-1.11-cuda11.3')"
"pytorch_env = Environment.get(ws, name='azureml-acpt-pytorch-1.13-cuda11.7')"
]
},
{

View File

@@ -1,378 +1,378 @@
{
"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": [
"![Impressions](https://PixelServer20190423114238.azurewebsites.net/api/impressions/MachineLearningNotebooks/how-to-use-azureml/ml-frameworks/pytorch/distributed-pytorch-with-horovod/distributed-pytorch-with-horovod.png)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Distributed PyTorch with Horovod\n",
"In this tutorial, you will train a PyTorch model on the [MNIST](http://yann.lecun.com/exdb/mnist/) dataset using distributed training via [Horovod](https://github.com/uber/horovod) across a GPU cluster."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Prerequisites\n",
"* If you are using an Azure Machine Learning Notebook VM, you are all set. Otherwise, go through the [Configuration](../../../../configuration.ipynb) notebook to install the Azure Machine Learning Python SDK and create an Azure ML `Workspace`\n",
"* Review the [tutorial](../train-hyperparameter-tune-deploy-with-pytorch/train-hyperparameter-tune-deploy-with-pytorch.ipynb) on single-node PyTorch training using Azure Machine Learning"
]
},
{
"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": [
"## Diagnostics\n",
"Opt-in diagnostics for better experience, quality, and security of future releases."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": [
"Diagnostics"
]
},
"outputs": [],
"source": [
"from azureml.telemetry import set_diagnostics_collection\n",
"\n",
"set_diagnostics_collection(send_diagnostics=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Initialize workspace\n",
"\n",
"Initialize a [Workspace](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#workspace) object from the existing workspace you created in the Prerequisites step. `Workspace.from_config()` creates a workspace object from the details stored in `config.json`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from azureml.core.workspace import Workspace\n",
"\n",
"ws = Workspace.from_config()\n",
"print('Workspace name: ' + ws.name, \n",
" 'Azure region: ' + ws.location, \n",
" 'Subscription id: ' + ws.subscription_id, \n",
" 'Resource group: ' + ws.resource_group, sep='\\n')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Create or attach existing AmlCompute\n",
"You will need to create a [compute target](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#compute-target) for training your model. In this tutorial, we use Azure ML managed compute ([AmlCompute](https://docs.microsoft.com/azure/machine-learning/service/how-to-set-up-training-targets#amlcompute)) for our remote training compute resource. Specifically, the below code creates an `Standard_NC6s_v3` GPU cluster that autoscales from `0` to `4` nodes.\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",
"**Creation of AmlCompute takes approximately 5 minutes.** If the AmlCompute with that name is already in your workspace, this code will skip the creation process.\n",
"\n",
"As with other Azure services, there are limits on certain resources (e.g. AmlCompute) associated with the Azure Machine Learning service. Please read [this article](https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-manage-quotas) on the default limits and how to request more quota."
]
},
{
"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",
"# choose a name for your cluster\n",
"cluster_name = \"gpu-cluster\"\n",
"\n",
"try:\n",
" compute_target = ComputeTarget(workspace=ws, name=cluster_name)\n",
" print('Found existing compute target.')\n",
"except ComputeTargetException:\n",
" print('Creating a new compute target...')\n",
" compute_config = AmlCompute.provisioning_configuration(vm_size='Standard_NC6s_v3',\n",
" max_nodes=4)\n",
"\n",
" # create the cluster\n",
" compute_target = ComputeTarget.create(ws, cluster_name, compute_config)\n",
"\n",
" compute_target.wait_for_completion(show_output=True)\n",
"\n",
"# use get_status() to get a detailed status for the current AmlCompute. \n",
"print(compute_target.get_status().serialize())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The above code creates GPU compute. If you instead want to create CPU compute, provide a different VM size to the `vm_size` parameter, such as `STANDARD_D2_V2`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Train model on the remote compute\n",
"Now that we have the AmlCompute ready to go, let's run our distributed training job."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Create a project directory\n",
"Create a directory that will contain all the necessary code from your local machine that you will need access to on the remote resource. This includes the training script and any additional files your training script depends on."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"project_folder = './pytorch-distr-hvd'\n",
"os.makedirs(project_folder, exist_ok=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Prepare training script\n",
"Now you will need to create your training script. In this tutorial, the script for distributed training of MNIST is already provided for you at `pytorch_horovod_mnist.py`. In practice, you should be able to take any custom PyTorch training script as is and run it with Azure ML without having to modify your code.\n",
"\n",
"However, if you would like to use Azure ML's [metric logging](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#logging) capabilities, you will have to add a small amount of Azure ML logic inside your training script. In this example, at each logging interval, we will log the loss for that minibatch to our Azure ML run.\n",
"\n",
"To do so, in `pytorch_horovod_mnist.py`, we will first access the Azure ML `Run` object within the script:\n",
"```Python\n",
"from azureml.core.run import Run\n",
"run = Run.get_context()\n",
"```\n",
"Later within the script, we log the loss metric to our run:\n",
"```Python\n",
"run.log('loss', loss.item())\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Once your script is ready, copy the training script `pytorch_horovod_mnist.py` into the project directory."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import shutil\n",
"\n",
"shutil.copy('pytorch_horovod_mnist.py', project_folder)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Create an experiment\n",
"Create an [Experiment](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#experiment) to track all the runs in your workspace for this distributed PyTorch tutorial. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from azureml.core import Experiment\n",
"\n",
"experiment_name = 'pytorch-distr-hvd'\n",
"experiment = Experiment(ws, name=experiment_name)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Create an environment\n",
"\n",
"In this tutorial, we will use one of Azure ML's curated PyTorch environments for training. [Curated environments](https://docs.microsoft.com/azure/machine-learning/how-to-use-environments#use-a-curated-environment) are available in your workspace by default. Specifically, we will use the PyTorch 1.6 GPU curated environment. The curated environment includes the `torch`, `torchvision` and `horovod` packages required by the training script."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from azureml.core import Environment\n",
"\n",
"pytorch_env = Environment.get(ws, name='AzureML-PyTorch-1.6-GPU')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Configure the training job\n",
"\n",
"Create a ScriptRunConfig object to specify the configuration details of your training job, including your training script, environment to use, and the compute target to run on.\n",
"\n",
"In order to execute a distributed run using MPI/Horovod, you must create an `MpiConfiguration` object and pass it to the `distributed_job_config` parameter of the ScriptRunConfig constructor. The below code will configure a 2-node distributed job running one process per node. If you would also like to run multiple processes per node (i.e. if your cluster SKU has multiple GPUs), additionally specify the `process_count_per_node` parameter in `MpiConfiguration` (the default is `1`)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from azureml.core import ScriptRunConfig\n",
"from azureml.core.runconfig import MpiConfiguration\n",
"\n",
"src = ScriptRunConfig(source_directory=project_folder,\n",
" script='pytorch_horovod_mnist.py',\n",
" compute_target=compute_target,\n",
" environment=pytorch_env,\n",
" distributed_job_config=MpiConfiguration(node_count=2))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Submit job\n",
"Run your experiment by submitting your ScriptRunConfig object. Note that this call is asynchronous."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"run = experiment.submit(src)\n",
"print(run)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Monitor your run\n",
"You can monitor the progress of the run with a Jupyter widget. Like the run submission, the widget is asynchronous and provides live updates every 10-15 seconds until the job completes. You can see that the widget automatically plots and visualizes the loss metric that we logged to the Azure ML run."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from azureml.widgets import RunDetails\n",
"\n",
"RunDetails(run).show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Alternatively, you can block until the script has completed training before running more code."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"run.wait_for_completion(show_output=True) # this provides a verbose log"
]
}
],
"metadata": {
"authors": [
{
"name": "ninhu"
}
],
"category": "training",
"compute": [
"AML Compute"
],
"datasets": [
"MNIST"
],
"deployment": [
"None"
],
"exclude_from_index": false,
"framework": [
"PyTorch"
],
"friendly_name": "Distributed PyTorch",
"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.9"
},
"tags": [
"None"
],
"task": "Train a model using the distributed training via Horovod"
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Copyright (c) Microsoft Corporation. All rights reserved.\n",
"\n",
"Licensed under the MIT License."
]
},
"nbformat": 4,
"nbformat_minor": 2
}
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![Impressions](https://PixelServer20190423114238.azurewebsites.net/api/impressions/MachineLearningNotebooks/how-to-use-azureml/ml-frameworks/pytorch/distributed-pytorch-with-horovod/distributed-pytorch-with-horovod.png)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Distributed PyTorch with Horovod\n",
"In this tutorial, you will train a PyTorch model on the [MNIST](http://yann.lecun.com/exdb/mnist/) dataset using distributed training via [Horovod](https://github.com/uber/horovod) across a GPU cluster."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Prerequisites\n",
"* If you are using an Azure Machine Learning Notebook VM, you are all set. Otherwise, go through the [Configuration](../../../../configuration.ipynb) notebook to install the Azure Machine Learning Python SDK and create an Azure ML `Workspace`\n",
"* Review the [tutorial](../train-hyperparameter-tune-deploy-with-pytorch/train-hyperparameter-tune-deploy-with-pytorch.ipynb) on single-node PyTorch training using Azure Machine Learning"
]
},
{
"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": [
"## Diagnostics\n",
"Opt-in diagnostics for better experience, quality, and security of future releases."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": [
"Diagnostics"
]
},
"outputs": [],
"source": [
"from azureml.telemetry import set_diagnostics_collection\n",
"\n",
"set_diagnostics_collection(send_diagnostics=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Initialize workspace\n",
"\n",
"Initialize a [Workspace](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#workspace) object from the existing workspace you created in the Prerequisites step. `Workspace.from_config()` creates a workspace object from the details stored in `config.json`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from azureml.core.workspace import Workspace\n",
"\n",
"ws = Workspace.from_config()\n",
"print('Workspace name: ' + ws.name, \n",
" 'Azure region: ' + ws.location, \n",
" 'Subscription id: ' + ws.subscription_id, \n",
" 'Resource group: ' + ws.resource_group, sep='\\n')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Create or attach existing AmlCompute\n",
"You will need to create a [compute target](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#compute-target) for training your model. In this tutorial, we use Azure ML managed compute ([AmlCompute](https://docs.microsoft.com/azure/machine-learning/service/how-to-set-up-training-targets#amlcompute)) for our remote training compute resource. Specifically, the below code creates an `Standard_NC6s_v3` GPU cluster that autoscales from `0` to `4` nodes.\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",
"**Creation of AmlCompute takes approximately 5 minutes.** If the AmlCompute with that name is already in your workspace, this code will skip the creation process.\n",
"\n",
"As with other Azure services, there are limits on certain resources (e.g. AmlCompute) associated with the Azure Machine Learning service. Please read [this article](https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-manage-quotas) on the default limits and how to request more quota."
]
},
{
"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",
"# choose a name for your cluster\n",
"cluster_name = \"gpu-cluster\"\n",
"\n",
"try:\n",
" compute_target = ComputeTarget(workspace=ws, name=cluster_name)\n",
" print('Found existing compute target.')\n",
"except ComputeTargetException:\n",
" print('Creating a new compute target...')\n",
" compute_config = AmlCompute.provisioning_configuration(vm_size='Standard_NC6s_v3',\n",
" max_nodes=4)\n",
"\n",
" # create the cluster\n",
" compute_target = ComputeTarget.create(ws, cluster_name, compute_config)\n",
"\n",
" compute_target.wait_for_completion(show_output=True)\n",
"\n",
"# use get_status() to get a detailed status for the current AmlCompute. \n",
"print(compute_target.get_status().serialize())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The above code creates GPU compute. If you instead want to create CPU compute, provide a different VM size to the `vm_size` parameter, such as `STANDARD_D2_V2`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Train model on the remote compute\n",
"Now that we have the AmlCompute ready to go, let's run our distributed training job."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Create a project directory\n",
"Create a directory that will contain all the necessary code from your local machine that you will need access to on the remote resource. This includes the training script and any additional files your training script depends on."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"project_folder = './pytorch-distr-hvd'\n",
"os.makedirs(project_folder, exist_ok=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Prepare training script\n",
"Now you will need to create your training script. In this tutorial, the script for distributed training of MNIST is already provided for you at `pytorch_horovod_mnist.py`. In practice, you should be able to take any custom PyTorch training script as is and run it with Azure ML without having to modify your code.\n",
"\n",
"However, if you would like to use Azure ML's [metric logging](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#logging) capabilities, you will have to add a small amount of Azure ML logic inside your training script. In this example, at each logging interval, we will log the loss for that minibatch to our Azure ML run.\n",
"\n",
"To do so, in `pytorch_horovod_mnist.py`, we will first access the Azure ML `Run` object within the script:\n",
"```Python\n",
"from azureml.core.run import Run\n",
"run = Run.get_context()\n",
"```\n",
"Later within the script, we log the loss metric to our run:\n",
"```Python\n",
"run.log('loss', loss.item())\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Once your script is ready, copy the training script `pytorch_horovod_mnist.py` into the project directory."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import shutil\n",
"\n",
"shutil.copy('pytorch_horovod_mnist.py', project_folder)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Create an experiment\n",
"Create an [Experiment](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#experiment) to track all the runs in your workspace for this distributed PyTorch tutorial. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from azureml.core import Experiment\n",
"\n",
"experiment_name = 'pytorch-distr-hvd'\n",
"experiment = Experiment(ws, name=experiment_name)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Create an environment\n",
"\n",
"In this tutorial, we will use one of Azure ML's curated PyTorch environments for training. [Curated environments](https://docs.microsoft.com/azure/machine-learning/how-to-use-environments#use-a-curated-environment) are available in your workspace by default. Specifically, we will use the PyTorch 1.6 GPU curated environment. The curated environment includes the `torch`, `torchvision` and `horovod` packages required by the training script."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from azureml.core import Environment\n",
"\n",
"pytorch_env = Environment.get(ws, name='AzureML-acpt-pytorch-1.13-cuda11.7')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Configure the training job\n",
"\n",
"Create a ScriptRunConfig object to specify the configuration details of your training job, including your training script, environment to use, and the compute target to run on.\n",
"\n",
"In order to execute a distributed run using MPI/Horovod, you must create an `MpiConfiguration` object and pass it to the `distributed_job_config` parameter of the ScriptRunConfig constructor. The below code will configure a 2-node distributed job running one process per node. If you would also like to run multiple processes per node (i.e. if your cluster SKU has multiple GPUs), additionally specify the `process_count_per_node` parameter in `MpiConfiguration` (the default is `1`)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from azureml.core import ScriptRunConfig\n",
"from azureml.core.runconfig import MpiConfiguration\n",
"\n",
"src = ScriptRunConfig(source_directory=project_folder,\n",
" script='pytorch_horovod_mnist.py',\n",
" compute_target=compute_target,\n",
" environment=pytorch_env,\n",
" distributed_job_config=MpiConfiguration(node_count=2))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Submit job\n",
"Run your experiment by submitting your ScriptRunConfig object. Note that this call is asynchronous."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"run = experiment.submit(src)\n",
"print(run)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Monitor your run\n",
"You can monitor the progress of the run with a Jupyter widget. Like the run submission, the widget is asynchronous and provides live updates every 10-15 seconds until the job completes. You can see that the widget automatically plots and visualizes the loss metric that we logged to the Azure ML run."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from azureml.widgets import RunDetails\n",
"\n",
"RunDetails(run).show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Alternatively, you can block until the script has completed training before running more code."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"run.wait_for_completion(show_output=True) # this provides a verbose log"
]
}
],
"metadata": {
"authors": [
{
"name": "ninhu"
}
],
"category": "training",
"compute": [
"AML Compute"
],
"datasets": [
"MNIST"
],
"deployment": [
"None"
],
"exclude_from_index": false,
"framework": [
"PyTorch"
],
"friendly_name": "Distributed PyTorch",
"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.9.18"
},
"tags": [
"None"
],
"task": "Train a model using the distributed training via Horovod"
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@@ -51,15 +51,15 @@ if args.cuda:
kwargs = {}
# Use Azure Open Datasets for MNIST dataset
# MNIST dataset
datasets.MNIST.resources = [
("https://azureopendatastorage.azurefd.net/mnist/train-images-idx3-ubyte.gz",
("train-images-idx3-ubyte.gz",
"f68b3c2dcbeaaa9fbdd348bbdeb94873"),
("https://azureopendatastorage.azurefd.net/mnist/train-labels-idx1-ubyte.gz",
("train-labels-idx1-ubyte.gz",
"d53e105ee54ea40749a09fcbcd1e9432"),
("https://azureopendatastorage.azurefd.net/mnist/t10k-images-idx3-ubyte.gz",
("t10k-images-idx3-ubyte.gz",
"9fb629c4189551a2d022fa330f9573f3"),
("https://azureopendatastorage.azurefd.net/mnist/t10k-labels-idx1-ubyte.gz",
("t10k-labels-idx1-ubyte.gz",
"ec29112dd5afa0611ce80d1b7f02629c")
]
train_dataset = \

View File

@@ -8,7 +8,7 @@ dependencies:
- matplotlib
- azureml-dataset-runtime
- ipywidgets
- raiwidgets~=0.28.0
- raiwidgets~=0.33.0
- liac-arff
- packaging>=20.9
- itsdangerous==2.0.1

View File

@@ -101,7 +101,7 @@
"\n",
"# Check core SDK version number\n",
"\n",
"print(\"This notebook was created using SDK version 1.53.0, you are currently running version\", azureml.core.VERSION)"
"print(\"This notebook was created using SDK version 1.55.0, you are currently running version\", azureml.core.VERSION)"
]
},
{

View File

@@ -28,9 +28,9 @@ mounted_input_path = sys.argv[1]
mounted_output_path = sys.argv[2]
os.makedirs(mounted_output_path, exist_ok=True)
convert(os.path.join(mounted_input_path, 'mnist-fashion/train-images-idx3-ubyte'),
os.path.join(mounted_input_path, 'mnist-fashion/train-labels-idx1-ubyte'),
convert(os.path.join(mounted_input_path, 'train-images-idx3-ubyte'),
os.path.join(mounted_input_path, 'train-labels-idx1-ubyte'),
os.path.join(mounted_output_path, 'mnist_train.csv'), 60000)
convert(os.path.join(mounted_input_path, 'mnist-fashion/t10k-images-idx3-ubyte'),
os.path.join(mounted_input_path, 'mnist-fashion/t10k-labels-idx1-ubyte'),
convert(os.path.join(mounted_input_path, 't10k-images-idx3-ubyte'),
os.path.join(mounted_input_path, 't10k-labels-idx1-ubyte'),
os.path.join(mounted_output_path, 'mnist_test.csv'), 10000)

View File

@@ -84,9 +84,6 @@ Machine Learning notebook samples and encourage efficient retrieval of topics an
|Title| Task | Dataset | Training Compute | Deployment Target | ML Framework | Tags |
|:----|:-----|:-------:|:----------------:|:-----------------:|:------------:|:------------:|
| [Deploy MNIST digit recognition with ONNX Runtime](https://github.com/Azure/MachineLearningNotebooks/blob/master//how-to-use-azureml/deployment/onnx/onnx-inference-mnist-deploy.ipynb) | Image Classification | MNIST | Local | Azure Container Instance | ONNX | ONNX Model Zoo |
| [Deploy Facial Expression Recognition (FER+) with ONNX Runtime](https://github.com/Azure/MachineLearningNotebooks/blob/master//how-to-use-azureml/deployment/onnx/onnx-inference-facial-expression-recognition-deploy.ipynb) | Facial Expression Recognition | Emotion FER | Local | Azure Container Instance | ONNX | ONNX Model Zoo |
| :star:[Register model and deploy as webservice](https://github.com/Azure/MachineLearningNotebooks/blob/master//how-to-use-azureml/deployment/deploy-to-cloud/model-register-and-deploy.ipynb) | Deploy a model with Azure Machine Learning | Diabetes | None | Azure Container Instance | Scikit-learn | None |
| [Train MNIST in PyTorch, convert, and deploy with ONNX Runtime](https://github.com/Azure/MachineLearningNotebooks/blob/master//how-to-use-azureml/deployment/onnx/onnx-train-pytorch-aml-deploy-mnist.ipynb) | Image Classification | MNIST | AML Compute | Azure Container Instance | ONNX | ONNX Converter |
| [Deploy ResNet50 with ONNX Runtime](https://github.com/Azure/MachineLearningNotebooks/blob/master//how-to-use-azureml/deployment/onnx/onnx-modelzoo-aml-deploy-resnet50.ipynb) | Image Classification | ImageNet | Local | Azure Container Instance | ONNX | ONNX Model Zoo |
| :star:[Convert and deploy TinyYolo with ONNX Runtime](https://github.com/Azure/MachineLearningNotebooks/blob/master//how-to-use-azureml/deployment/onnx/onnx-convert-aml-deploy-tinyyolo.ipynb) | Object Detection | PASCAL VOC | local | Azure Container Instance | ONNX | ONNX Converter |
@@ -95,7 +92,6 @@ Machine Learning notebook samples and encourage efficient retrieval of topics an
## Other Notebooks
|Title| Task | Dataset | Training Compute | Deployment Target | ML Framework | Tags |
|:----|:-----|:-------:|:----------------:|:-----------------:|:------------:|:------------:|
| [DNN Text Featurization](https://github.com/Azure/MachineLearningNotebooks/blob/master//how-to-use-azureml/automated-machine-learning/classification-text-dnn/auto-ml-classification-text-dnn.ipynb) | Text featurization using DNNs for classification | None | AML Compute | None | None | None |
| [configuration](https://github.com/Azure/MachineLearningNotebooks/blob/master/configuration.ipynb) | | | | | | |
| [fairlearn-azureml-mitigation](https://github.com/Azure/MachineLearningNotebooks/blob/master//contrib/fairness/fairlearn-azureml-mitigation.ipynb) | | | | | | |
| [upload-fairness-dashboard](https://github.com/Azure/MachineLearningNotebooks/blob/master//contrib/fairness/upload-fairness-dashboard.ipynb) | | | | | | |

View File

@@ -102,7 +102,7 @@
"source": [
"import azureml.core\n",
"\n",
"print(\"This notebook was created using version 1.53.0 of the Azure ML SDK\")\n",
"print(\"This notebook was created using version 1.55.0 of the Azure ML SDK\")\n",
"print(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")"
]
},