├── .gitignore ├── 00.configuration.ipynb ├── 01.train-deploy_pytorch.ipynb ├── 02.train-hyperparametertune-deploy_chainer.ipynb ├── 11.automated-machine-learning_classification_auto-ml-classification.ipynb ├── 12.automated-machine-learning_classification-with-deployment_auto-ml-classification-with-deployment.ipynb ├── LICENSE ├── README.md ├── data ├── dog-cat.zip ├── test_img.jpg └── test_img2.jpeg ├── docs ├── 01_train-deploy.ipynb ├── 02_demo_chainer.ipynb ├── 02_demo_pytorch.ipynb ├── data │ ├── dog-cat.zip │ ├── test_img.jpg │ └── test_img2.jpeg └── images │ ├── 02_01.png │ ├── 02_02.png │ ├── 02_03.png │ └── 02_04.png ├── img ├── iotedge01.jpg └── iotedge02.jpg └── ppt └── AzureMachineLearningServicesHOL.pptx /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .ipynb_checkpoints 3 | -------------------------------------------------------------------------------- /00.configuration.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "metadata": {}, 5 | "cell_type": "markdown", 6 | "source": "Copyright (c) Microsoft Corporation. All rights reserved.\n\nLicensed under the MIT License." 7 | }, 8 | { 9 | "metadata": {}, 10 | "cell_type": "markdown", 11 | "source": "# Configuration\n\n_**Setting up your Azure Machine Learning services workspace and configuring your notebook library**_\n\n---\n---\n\n## Table of Contents\n\n1. [Introduction](#Introduction)\n 1. What is an Azure Machine Learning workspace\n1. [Setup](#Setup)\n 1. Azure subscription\n 1. Azure ML SDK and other library installation\n 1. Azure Container Instance registration\n1. [Configure your Azure ML Workspace](#Configure%20your%20Azure%20ML%20workspace)\n 1. Workspace parameters\n 1. Access your workspace\n 1. Create a new workspace\n 1. Create compute resources\n1. [Next steps](#Next%20steps)\n\n---\n\n## Introduction\n\nThis notebook configures your library of notebooks to connect to an Azure Machine Learning (ML) workspace. In this case, a library contains all of the notebooks in the current folder and any nested folders. You can configure this notebook library to use an existing workspace or create a new workspace.\n\nTypically you will need to run this notebook only once per notebook library as all other notebooks will use connection information that is written here. If you want to redirect your notebook library to work with a different workspace, then you should re-run this notebook.\n\nIn this notebook you will\n* Learn about getting an Azure subscription\n* Specify your workspace parameters\n* Access or create your workspace\n* Add a default compute cluster for your workspace\n\n### What is an Azure Machine Learning workspace\n\nAn Azure ML Workspace is an Azure resource that organizes and coordinates the actions of many other Azure resources to assist in executing and sharing machine learning workflows. In particular, an Azure ML Workspace coordinates storage, databases, and compute resources providing added functionality for machine learning experimentation, deployment, inferencing, and the monitoring of deployed models." 12 | }, 13 | { 14 | "metadata": {}, 15 | "cell_type": "markdown", 16 | "source": "## Setup\n\nThis section describes activities required before you can access any Azure ML services functionality." 17 | }, 18 | { 19 | "metadata": {}, 20 | "cell_type": "markdown", 21 | "source": "### 1. Azure Subscription\n\nIn order to create an Azure ML Workspace, first you need access to an Azure subscription. An Azure subscription allows you to manage storage, compute, and other assets in the Azure cloud. You can [create a new subscription](https://azure.microsoft.com/en-us/free/) or access existing subscription information from the [Azure portal](https://portal.azure.com). Later in this notebook you will need information such as your subscription ID in order to create and access AML workspaces.\n\n### 2. Azure ML SDK and other library installation\n\nIf you are running in your own environment, follow [SDK installation instructions](https://docs.microsoft.com/azure/machine-learning/service/how-to-configure-environment). If you are running in Azure Notebooks or another Microsoft managed environment, the SDK is already installed.\n\nAlso install following libraries to your environment. Many of the example notebooks depend on them\n\n```\n(myenv) $ conda install -y matplotlib tqdm scikit-learn\n```\n\nOnce installation is complete, the following cell checks the Azure ML SDK version:" 22 | }, 23 | { 24 | "metadata": { 25 | "tags": [ 26 | "install" 27 | ], 28 | "trusted": true 29 | }, 30 | "cell_type": "code", 31 | "source": "import azureml.core\n\nprint(\"This notebook was created using version 1.0.15 of the Azure ML SDK\")\nprint(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")", 32 | "execution_count": null, 33 | "outputs": [] 34 | }, 35 | { 36 | "metadata": {}, 37 | "cell_type": "markdown", 38 | "source": "If you are using an older version of the SDK then this notebook was created using, you should upgrade your SDK.\n\n### Python SDK のバージョンの確認\n\nAzure Machine Learning services の各種機能の連携を理解するために、Python SDK の Chainer Estimator を使います。Chainer Estimator は SDK の **1.0.15** から導入されています。\n\nAzure Notebook の Azure Machine Learning Serivice SDK のバージョンが 1.0.15よりも古い場合は、以下のコマンドで最新版にアップデートしてください。" 39 | }, 40 | { 41 | "metadata": { 42 | "trusted": true 43 | }, 44 | "cell_type": "code", 45 | "source": "!pip install --upgrade azureml-sdk[notebooks,automl] azureml-dataprep", 46 | "execution_count": null, 47 | "outputs": [] 48 | }, 49 | { 50 | "metadata": {}, 51 | "cell_type": "markdown", 52 | "source": "Python SDK をアップデートした場合は、JupyterNotebook の **Kernel** を **Restart** して最新版をロードします。" 53 | }, 54 | { 55 | "metadata": {}, 56 | "cell_type": "markdown", 57 | "source": "### 3. Azure Container Instance registration\nAzure Machine Learning uses of [Azure Container Instance (ACI)](https://azure.microsoft.com/services/container-instances) to deploy dev/test web services. An Azure subscription needs to be registered to use ACI. If you or the subscription owner have not yet registered ACI on your subscription, you will need to use the [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) and execute the following commands. Note that if you ran through the AML [quickstart](https://docs.microsoft.com/en-us/azure/machine-learning/service/quickstart-get-started) you have already registered ACI. \n\n```shell\n# check to see if ACI is already registered\n(myenv) $ az provider show -n Microsoft.ContainerInstance -o table\n\n# if ACI is not registered, run this command.\n# note you need to be the subscription owner in order to execute this command successfully.\n(myenv) $ az provider register -n Microsoft.ContainerInstance\n```" 58 | }, 59 | { 60 | "metadata": {}, 61 | "cell_type": "markdown", 62 | "source": "## Configure your Azure ML workspace\n\n### Workspace parameters\n\nTo use an AML Workspace, you will need to import the Azure ML SDK and supply the following information:\n* Your subscription id\n* A resource group name\n* (optional) The region that will host your workspace\n* A name for your workspace\n\nYou can get your subscription ID from the [Azure portal](https://portal.azure.com).\n\nYou will also need access to a [_resource group_](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-overview#resource-groups), which organizes Azure resources and provides a default region for the resources in a group. You can see what resource groups to which you have access, or create a new one in the [Azure portal](https://portal.azure.com). If you don't have a resource group, the create workspace command will create one for you using the name you provide.\n\nThe region to host your workspace will be used if you are creating a new workspace. You do not need to specify this if you are using an existing workspace. You can find the list of supported regions [here](https://azure.microsoft.com/en-us/global-infrastructure/services/?products=machine-learning-service). You should pick a region that is close to your location or that contains your data.\n\nThe name for your workspace is unique within the subscription and should be descriptive enough to discern among other AML Workspaces. The subscription may be used only by you, or it may be used by your department or your entire enterprise, so choose a name that makes sense for your situation.\n\nThe following cell allows you to specify your workspace parameters. This cell uses the python method `os.getenv` to read values from environment variables which is useful for automation. If no environment variable exists, the parameters will be set to the specified default values. \n\nIf you ran the Azure Machine Learning [quickstart](https://docs.microsoft.com/en-us/azure/machine-learning/service/quickstart-get-started) in Azure Notebooks, you already have a configured workspace! You can go to your Azure Machine Learning Getting Started library, view *config.json* file, and copy-paste the values for subscription ID, resource group and workspace name below.\n\nReplace the default values in the cell below with your workspace parameters" 63 | }, 64 | { 65 | "metadata": { 66 | "trusted": true 67 | }, 68 | "cell_type": "code", 69 | "source": "import os\n\nsubscription_id = os.getenv(\"SUBSCRIPTION_ID\", default=\"\")\nresource_group = os.getenv(\"RESOURCE_GROUP\", default=\"<リソースグループ名>\")\nworkspace_name = os.getenv(\"WORKSPACE_NAME\", default=\"\")", 70 | "execution_count": null, 71 | "outputs": [] 72 | }, 73 | { 74 | "metadata": {}, 75 | "cell_type": "markdown", 76 | "source": "### Access your workspace\n\nThe following cell uses the Azure ML SDK to attempt to load the workspace specified by your parameters. If this cell succeeds, your notebook library will be configured to access the workspace from all notebooks using the `Workspace.from_config()` method. The cell can fail if the specified workspace doesn't exist or you don't have permissions to access it. " 77 | }, 78 | { 79 | "metadata": { 80 | "trusted": true 81 | }, 82 | "cell_type": "code", 83 | "source": "from azureml.core import Workspace\n\ntry:\n ws = Workspace(subscription_id = subscription_id, resource_group = resource_group, workspace_name = workspace_name)\n # write the details of the workspace to a configuration file to the notebook library\n ws.write_config()\n print(\"Workspace configuration succeeded. Skip the workspace creation steps below\")\nexcept:\n print(\"Workspace not accessible. Change your parameters or create a new workspace below\")", 84 | "execution_count": null, 85 | "outputs": [] 86 | }, 87 | { 88 | "metadata": {}, 89 | "cell_type": "markdown", 90 | "source": "### Create compute resources for your training experiments\n\nMany of the sample notebooks use Azure ML managed compute (AmlCompute) to train models using a dynamically scalable pool of compute. In this section you will create default compute clusters for use by the other notebooks and any other operations you choose.\n\nTo create a cluster, you need to specify a compute configuration that specifies the type of machine to be used and the scalability behaviors. Then you choose a name for the cluster that is unique within the workspace that can be used to address the cluster later.\n\nThe cluster parameters are:\n* vm_size - this describes the virtual machine type and size used in the cluster. All machines in the cluster are the same type. You can get the list of vm sizes available in your region by using the CLI command\n\n```shell\naz vm list-skus -o tsv\n```\n* min_nodes - this sets the minimum size of the cluster. If you set the minimum to 0 the cluster will shut down all nodes while note in use. Setting this number to a value higher than 0 will allow for faster start-up times, but you will also be billed when the cluster is not in use.\n* max_nodes - this sets the maximum size of the cluster. Setting this to a larger number allows for more concurrency and a greater distributed processing of scale-out jobs." 91 | }, 92 | { 93 | "metadata": {}, 94 | "cell_type": "markdown", 95 | "source": "## コンピューティング ターゲットの設定\n\n[コンピューティングターゲット](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#compute-target)を作成する必要があります。このチュートリアルではAzure ML managed compute ([AmlCompute](https://docs.microsoft.com/azure/machine-learning/service/how-to-set-up-training-targets#amlcompute))を使用します。 \n(コンピューティングターゲットは計算を実行する場所を決定するようなイメージです。)\n\n※AmlComputeの作成には約5分かかります。 \nその名前のAmlComputeが既にワークスペースにある場合、このコードは作成プロセスをスキップします。\n\n\n他のAzureサービスと同様に、Azure Machine Learningサービスに関連する特定のリソース(AmlComputeなど)には制限があります。 \nデフォルトの制限と、より多くのクォータを要求する方法についての[この記事](https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-manage-quotas)を読んでください。" 96 | }, 97 | { 98 | "metadata": {}, 99 | "cell_type": "markdown", 100 | "source": "今回は`lowpriority`を使用して、 約 **8割引きの価格**で`STANDARD_NC6`を使用します。 \nコンピューティング先を決定する際に注意点として`min_nodes=0`の設定部分です。 \nこちらがもし、1以上の値の場合はノードが常に立ち上がり課金が発生してしまいます。 \n\nまた`vm_size`ですが、さらに計算機能が高いものを使用するには変更する必要があります。 \nGPUのVMサイズは[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/virtual-machines/linux/sizes-gpu)を確認してください。 " 101 | }, 102 | { 103 | "metadata": { 104 | "trusted": true 105 | }, 106 | "cell_type": "code", 107 | "source": "from azureml.core.compute import ComputeTarget, AmlCompute\nfrom azureml.core.compute_target import ComputeTargetException\n\nAmlCompute.supported_vmsizes(workspace = ws)\n\n# Choose a name for your GPU cluster\ngpu_cluster_name = \"gpucluster\"\n\n# Verify that cluster does not exist already\ntry:\n gpu_cluster = ComputeTarget(workspace=ws, name=gpu_cluster_name)\n print(\"Found existing gpu cluster\")\nexcept ComputeTargetException:\n print(\"Creating new gpucluster\")\n \n # Specify the configuration for the new cluster\n compute_config = AmlCompute.provisioning_configuration(vm_size=\"Standard_NC6\", ## Standard_NC6s_v3\n min_nodes=1,\n max_nodes=1,\n vm_priority='lowpriority') ## vm_priority='lowpriority' | `dedicated'\n # Create the cluster with the specified name and configuration\n gpu_cluster = ComputeTarget.create(ws, gpu_cluster_name, compute_config)\n\n # Wait for the cluster to complete, show the output log\n gpu_cluster.wait_for_completion(show_output=True) ", 108 | "execution_count": null, 109 | "outputs": [] 110 | }, 111 | { 112 | "metadata": {}, 113 | "cell_type": "markdown", 114 | "source": "## (Option) CPU のクラスター作成\n\nTo create a **CPU** cluster now, run the cell below. The autoscale settings mean that the cluster will scale down to 0 nodes when inactive and up to 4 nodes when busy." 115 | }, 116 | { 117 | "metadata": { 118 | "trusted": true 119 | }, 120 | "cell_type": "code", 121 | "source": "from azureml.core.compute import ComputeTarget, AmlCompute\nfrom azureml.core.compute_target import ComputeTargetException\n\n# Choose a name for your CPU cluster\ncpu_cluster_name = \"cpucluster\"\n\n# Verify that cluster does not exist already\ntry:\n cpu_cluster = ComputeTarget(workspace=ws, name=cpu_cluster_name)\n print(\"Found existing cpucluster\")\nexcept ComputeTargetException:\n print(\"Creating new cpucluster\")\n \n # Specify the configuration for the new cluster\n compute_config = AmlCompute.provisioning_configuration(vm_size=\"STANDARD_D2_V2\",\n min_nodes=2,\n max_nodes=2) ## vm_priority='lowpriority' | `dedicated'\n\n # Create the cluster with the specified name and configuration\n cpu_cluster = ComputeTarget.create(ws, cpu_cluster_name, compute_config)\n \n # Wait for the cluster to complete, show the output log\n cpu_cluster.wait_for_completion(show_output=True)", 122 | "execution_count": null, 123 | "outputs": [] 124 | }, 125 | { 126 | "metadata": { 127 | "trusted": true 128 | }, 129 | "cell_type": "code", 130 | "source": "", 131 | "execution_count": null, 132 | "outputs": [] 133 | } 134 | ], 135 | "metadata": { 136 | "authors": [ 137 | { 138 | "name": "roastala" 139 | } 140 | ], 141 | "kernelspec": { 142 | "name": "python36", 143 | "display_name": "Python 3.6", 144 | "language": "python" 145 | }, 146 | "language_info": { 147 | "mimetype": "text/x-python", 148 | "nbconvert_exporter": "python", 149 | "name": "python", 150 | "pygments_lexer": "ipython3", 151 | "version": "3.6.6", 152 | "file_extension": ".py", 153 | "codemirror_mode": { 154 | "version": 3, 155 | "name": "ipython" 156 | } 157 | } 158 | }, 159 | "nbformat": 4, 160 | "nbformat_minor": 2 161 | } -------------------------------------------------------------------------------- /01.train-deploy_pytorch.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "metadata": {}, 5 | "cell_type": "markdown", 6 | "source": "# [PyTorch] Azure MLで学習済みモデルの作成からデプロイまで\n\nこのチュートリアルでは、`Azure Machine Learning(Azure ML)Python SDK`を使用して、モデルのトレーニング、ハイパーパラメーターの調整、およびデプロイを行います。 \n※ディープラーニングのフレームワークには`PyTorch`を使用します。 \n\n\n問題設定は[Transfer Learningチュートリアル](https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html)から、 Transfer Learning(転移学習)を使用してアリとハチの画像分類になります。 \n\n## 転移学習とは? \n転移学習とは学習済みモデルを使用して(ネットワークの構造と重みの再利用)、学習を行うことをさします。 \n類似のものとしてファインチューニングがありますが、学習済みモデルのネットワークの学習を行うのがファインチューニングになります。 \n転移学習では学習済みモデルのネットワーク自体の学習は行いません。(出力前の全結合層のみを学習させるのが一般的) " 7 | }, 8 | { 9 | "metadata": {}, 10 | "cell_type": "markdown", 11 | "source": "## 環境構築\n\n環境は「[Azure Machine Learning Services](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/) ワークスペース」にある`Azure Notebooks`を使用します。 \nPythonの実行環境や、Azure ML Servicesを使用に必要な[Azure ML Python SDK](https://docs.microsoft.com/ja-jp/python/api/overview/azure/ml/intro?view=azure-ml-py)は既にインストールされています。  \n\nこの画面の右上の Kernel が `Python 3.6` になっていることを確認します。異なる場合は、[Kernel] メニューから、変更してください。" 12 | }, 13 | { 14 | "metadata": {}, 15 | "cell_type": "markdown", 16 | "source": "### バージョンの確認" 17 | }, 18 | { 19 | "metadata": { 20 | "trusted": true 21 | }, 22 | "cell_type": "code", 23 | "source": "import azureml.core\n\nprint(\"This notebook was created using version 1.0.15 of the Azure ML SDK\")\nprint(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")", 24 | "execution_count": null, 25 | "outputs": [] 26 | }, 27 | { 28 | "metadata": {}, 29 | "cell_type": "markdown", 30 | "source": "このコードは、SDK `1.0.10`か`1.0.15` で動作確認しています。もし、SDKの更新を行う場合は、以下を実行して、SDKを更新してください。" 31 | }, 32 | { 33 | "metadata": { 34 | "trusted": true 35 | }, 36 | "cell_type": "code", 37 | "source": "!pip install --upgrade azureml-sdk[notebooks,automl] azureml-dataprep", 38 | "execution_count": null, 39 | "outputs": [] 40 | }, 41 | { 42 | "metadata": {}, 43 | "cell_type": "markdown", 44 | "source": "Python SDK をアップデートした場合は、JupyterNotebook の **Kernel** を **Restart** して最新版をロードします。" 45 | }, 46 | { 47 | "metadata": {}, 48 | "cell_type": "markdown", 49 | "source": "Azrue Notebook では既にAzureML Python SDKが準備されているため、インストールする必要はありません。 " 50 | }, 51 | { 52 | "metadata": {}, 53 | "cell_type": "markdown", 54 | "source": "### ワークスペースの初期化\n\n**00.configuration.ipynb を実行して、`config.json` ファイルを作成済みの場合は、このセルはスキップして次に進んでください。**\n\n[ワークスペース](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#workspace)の初期化を行います。 \n`Workspace.from_config()`は`config.json`ファイルを参照してワークスペースを初期化します。 \n\n詳細は[こちら](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-configure-environment#workspace) を参照してください。\n\n#### configファイルの編集\n\n`config.json`ファイルは基本的に自動でこのように設定を反映されます。 \n自身で設定する際には下記のように編集します。 \n\n```json\n\n{\n \"subscription_id\": \"サブスクリプションID\",\n \"resource_group\": \"リソースグループ名\",\n \"workspace_name\": \"ワークスペース名\"\n}\n\n```\n\n上記の情報はAzure Portalの画面から確認することができます。 \nでは、実行して、ワークスペースの初期化を行います。 \n\n初期化を行う時に、サインインを要求されるので、表示されるコードをコピーして、URLをクリックします。 \n遷移先の画面でコピーしたコードを入力することによって、サインインが完了します。 " 55 | }, 56 | { 57 | "metadata": { 58 | "trusted": true 59 | }, 60 | "cell_type": "code", 61 | "source": "from azureml.core.workspace import Workspace\n\nws = Workspace.from_config()\nprint('Workspace name: ' + ws.name, \n 'Azure region: ' + ws.location, \n 'Resource group: ' + ws.resource_group, sep = '\\n')", 62 | "execution_count": null, 63 | "outputs": [] 64 | }, 65 | { 66 | "metadata": {}, 67 | "cell_type": "markdown", 68 | "source": "## コンピューティング ターゲットの設定\n\n[コンピューティングターゲット](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#compute-target)を作成する必要があります。このチュートリアルではAzure ML managed compute ([AmlCompute](https://docs.microsoft.com/azure/machine-learning/service/how-to-set-up-training-targets#amlcompute))を使用します。 \n(コンピューティングターゲットは計算を実行する場所を決定するようなイメージです。)\n\n※AmlComputeの作成には約5分かかります。 \nその名前のAmlComputeが既にワークスペースにある場合、このコードは作成プロセスをスキップします。\n\n他のAzureサービスと同様に、Azure Machine Learningサービスに関連する特定のリソース(AmlComputeなど)には制限があります。 \nデフォルトの制限と、より多くのクォータを要求する方法についての[この記事](https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-manage-quotas)を読んでください。" 69 | }, 70 | { 71 | "metadata": { 72 | "trusted": true 73 | }, 74 | "cell_type": "code", 75 | "source": "from azureml.core.compute import ComputeTarget, AmlCompute\nfrom azureml.core.compute_target import ComputeTargetException\n\n# choose a name for your cluster\ncluster_name = \"gpucluster\"\n\ntry:\n compute_target = ComputeTarget(workspace=ws, name=cluster_name)\n print('Found existing compute target.')\nexcept ComputeTargetException:\n print('Creating a new compute target...')\n compute_config = AmlCompute.provisioning_configuration(vm_size=\"Standard_NC6\", ## Standard_NC6s_v3\n min_nodes=1,\n max_nodes=1,\n vm_priority='lowpriority') ## vm_priority='lowpriority' | `dedicated'\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 the 'status' property to get a detailed status for the current cluster. \nprint(compute_target.status.serialize())", 76 | "execution_count": null, 77 | "outputs": [] 78 | }, 79 | { 80 | "metadata": {}, 81 | "cell_type": "markdown", 82 | "source": "上記のコードはGPUクラスターを作成します。 \nコードの中身を確認します。 \n`AmlCompute.provisioning_configuration()`でコンピューティング ターゲットの設定を行うことができます。 \n詳細は[こちらの公式ドキュメント](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.compute.amlcompute(class)?view=azure-ml-py)を確認してください。 \n\n\n### 仮想マシンのサイズの変更\n\n代わりにCPUクラスタを作成したい場合は、 `STANDARD_D2_V2`のように` vm_size`パラメータに異なるVMサイズを指定してください。 \n\nCPUのVMサイズは[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/virtual-machines/linux/sizes-general)を確認してください。 \nGPUのVMサイズは[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/virtual-machines/linux/sizes-gpu)を確認してください。 \n\n今回はNVIDIAのTesla K80が1枚の仮想マシン`STANDARD_NC6`を使用します。 \n計算リソースを増やすためにはNCの他のシリーズを使用するもしくはGPUの枚数を増やすことによって行うことが可能です。 \n\n\n### 仮想マシンの割り当ての設定\n\nAzureの仮想マシンのプライオリティ(優先度)を選択することができます。 \n選択肢は`dedicated`または`lowpriority`の2つから選択することができます。 \n(デフォルトでは`dedicated`が選択されています。) \n\n`dedicated`は問題なく仮想マシンが割り当てられますが、`lowpriority`は価格が安い代わりに割り込みが入る可能性などいくつかデメリットがあります。 \nしかし、価格が約8割ほど安くなるのは大きなメリットです。 \n\n\n### クラスターのノード数の設定\n\n`max_nodes`でコンピューティングでジョブを実行中に自動スケールアップする最大ノード数を指定することが可能です。 \nノード数はVMの数を表すため最大数が増えると計算リソースが増えますが、同時に発生する料金も増えます。 " 83 | }, 84 | { 85 | "metadata": {}, 86 | "cell_type": "markdown", 87 | "source": "# (Option) Data Science VM の設定\n\n**AmlCompute の作成ができた方は **スキップ** してください!!!実行すると、AmlCompute設定が**上書き**されてしまいます。**\n\nAzure Machine Learning Services では、Data Science VMのGPUインスタンス版など、リモートの仮想マシンを学習の実行環境に設定することもできます。\n\nAzure 無償トライアルなどで、GPUインスタンスのクォータ引き上げが出来ない場合もありますのでご注意ください。\n\n[こちら](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-set-up-training-targets#vm) のドキュメントを参照して、*事前*に Data Science VM を作成してから、以下を実行してください。" 88 | }, 89 | { 90 | "metadata": { 91 | "trusted": true 92 | }, 93 | "cell_type": "code", 94 | "source": "from azureml.core.compute import RemoteCompute, ComputeTarget\n\n# Create the compute config \ncompute_target_name = 'attachdsvm'\nattach_config = RemoteCompute.attach_configuration(address='',\n ssh_port=22,\n username='User Name',\n password='Password')\n\n# Attach the compute\ncompute_target = ComputeTarget.attach(ws, compute_target_name, attach_config)\n\ncompute_target.wait_for_completion(show_output=True)", 95 | "execution_count": null, 96 | "outputs": [] 97 | }, 98 | { 99 | "metadata": {}, 100 | "cell_type": "markdown", 101 | "source": "## GPUクラスタを使用しての学習の実行\n\nリモートコンピューティングクラスタを使用して学習する準備が整いました。 \nPytorchでの学習のスクリプトと学習用のデータを準備します。 \n\n今回は事前に準備されたものを使用します。  " 102 | }, 103 | { 104 | "metadata": {}, 105 | "cell_type": "markdown", 106 | "source": "### プロジェクトディレクトリの作成\n\n学習実行に必要なコードを格納するディレクトリを作成します。 \nこのディレクトリには学習を実行するコードと、それに依存関係のファイルなどを格納するする必要があります。 " 107 | }, 108 | { 109 | "metadata": { 110 | "trusted": true 111 | }, 112 | "cell_type": "code", 113 | "source": "import os\n\nproject_folder = './pytorch-hymenoptera'\nos.makedirs(project_folder, exist_ok=True)", 114 | "execution_count": null, 115 | "outputs": [] 116 | }, 117 | { 118 | "metadata": {}, 119 | "cell_type": "markdown", 120 | "source": "今回は`pytorch-hymenoptera`という名前のプロジェクトフォルダを作成しました。 " 121 | }, 122 | { 123 | "metadata": {}, 124 | "cell_type": "markdown", 125 | "source": "### データセットの準備\n\n今回は[こちら](https://download.pytorch.org/tutorial/hymenoptera_data.zip)のデータセットを使用します。 \n(ダウンロードの必要はありません)\n\n\nこちらにはアリとミツバチの画像それぞれ約120個ずつの訓練データ、75個の検証データが含まれています。 \n学習用のスクリプトである`pytorch_train.py`内にデータセットをダウンロードして取得するコードがあるため、 \nこちらのデータは今回はダウンロードして準備する必要はありません。 " 126 | }, 127 | { 128 | "metadata": {}, 129 | "cell_type": "markdown", 130 | "source": "\n### 学習用スクリプトの準備\n\n学習用のスクリプトは用意されている`pytorch_train.py`を使用します。 \n\n\n### スクリプトの確認\n\n今回使用するスクリプトはこちらになります。 \n`pytorch_train.py` \nこちらのスクリプトの詳細の説明は行いませんが、実行内容としては下記の4ステップになります。 \n\n1. データのダウンロード\n2. 必要な前処理の適応\n3. 学習の実行\n4. 結果の取得" 131 | }, 132 | { 133 | "metadata": { 134 | "trusted": true 135 | }, 136 | "cell_type": "code", 137 | "source": "%%writefile pytorch_train.py \n\nfrom __future__ import print_function, division\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.optim import lr_scheduler\nfrom torchvision import datasets, models, transforms\nimport numpy as np\nimport time\nimport os\nimport copy\nimport argparse\n\nfrom azureml.core.run import Run\n# get the Azure ML run object\nrun = Run.get_context()\n\n\ndef load_data(data_dir):\n \"\"\"Load the train/val data.\"\"\"\n\n # Data augmentation and normalization for training\n # Just normalization for validation\n data_transforms = {\n 'train': transforms.Compose([\n transforms.RandomResizedCrop(224),\n transforms.RandomHorizontalFlip(),\n transforms.ToTensor(),\n transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n ]),\n 'val': transforms.Compose([\n transforms.Resize(256),\n transforms.CenterCrop(224),\n transforms.ToTensor(),\n transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n ]),\n }\n\n image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),\n data_transforms[x])\n for x in ['train', 'val']}\n dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,\n shuffle=True, num_workers=4)\n for x in ['train', 'val']}\n dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}\n class_names = image_datasets['train'].classes\n\n return dataloaders, dataset_sizes, class_names\n\n\ndef train_model(model, criterion, optimizer, scheduler, num_epochs, data_dir):\n \"\"\"Train the model.\"\"\"\n\n # load training/validation data\n dataloaders, dataset_sizes, class_names = load_data(data_dir)\n\n device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\n\n since = time.time()\n\n best_model_wts = copy.deepcopy(model.state_dict())\n best_acc = 0.0\n\n for epoch in range(num_epochs):\n print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n print('-' * 10)\n\n # Each epoch has a training and validation phase\n for phase in ['train', 'val']:\n if phase == 'train':\n scheduler.step()\n model.train() # Set model to training mode\n else:\n model.eval() # Set model to evaluate mode\n\n running_loss = 0.0\n running_corrects = 0\n\n # Iterate over data.\n for inputs, labels in dataloaders[phase]:\n inputs = inputs.to(device)\n labels = labels.to(device)\n\n # zero the parameter gradients\n optimizer.zero_grad()\n\n # forward\n # track history if only in train\n with torch.set_grad_enabled(phase == 'train'):\n outputs = model(inputs)\n _, preds = torch.max(outputs, 1)\n loss = criterion(outputs, labels)\n\n # backward + optimize only if in training phase\n if phase == 'train':\n loss.backward()\n optimizer.step()\n\n # statistics\n running_loss += loss.item() * inputs.size(0)\n running_corrects += torch.sum(preds == labels.data)\n\n epoch_loss = running_loss / dataset_sizes[phase]\n epoch_acc = running_corrects.double() / dataset_sizes[phase]\n\n print('{} Loss: {:.4f} Acc: {:.4f}'.format(\n phase, epoch_loss, epoch_acc))\n\n # deep copy the model\n if phase == 'val' and epoch_acc > best_acc:\n best_acc = epoch_acc\n best_model_wts = copy.deepcopy(model.state_dict())\n\n # log the best val accuracy to AML run\n run.log('best_val_acc', np.float(best_acc))\n\n print()\n\n time_elapsed = time.time() - since\n print('Training complete in {:.0f}m {:.0f}s'.format(\n time_elapsed // 60, time_elapsed % 60))\n print('Best val Acc: {:4f}'.format(best_acc))\n\n # load best model weights\n model.load_state_dict(best_model_wts)\n return model\n\n\ndef fine_tune_model(num_epochs, data_dir, learning_rate, momentum):\n \"\"\"Load a pretrained model and reset the final fully connected layer.\"\"\"\n\n # log the hyperparameter metrics to the AML run\n run.log('lr', np.float(learning_rate))\n run.log('momentum', np.float(momentum))\n\n model_ft = models.resnet18(pretrained=True)\n num_ftrs = model_ft.fc.in_features\n model_ft.fc = nn.Linear(num_ftrs, 2) # only 2 classes to predict\n\n device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\n model_ft = model_ft.to(device)\n\n criterion = nn.CrossEntropyLoss()\n\n # Observe that all parameters are being optimized\n optimizer_ft = optim.SGD(model_ft.parameters(),\n lr=learning_rate, momentum=momentum)\n\n # Decay LR by a factor of 0.1 every 7 epochs\n exp_lr_scheduler = lr_scheduler.StepLR(\n optimizer_ft, step_size=7, gamma=0.1)\n\n model = train_model(model_ft, criterion, optimizer_ft,\n exp_lr_scheduler, num_epochs, data_dir)\n\n return model\n\n\ndef download_data():\n \"\"\"Download and extract the training data.\"\"\"\n import urllib\n from zipfile import ZipFile\n # download data\n data_file = './hymenoptera_data.zip'\n download_url = 'https://download.pytorch.org/tutorial/hymenoptera_data.zip'\n urllib.request.urlretrieve(download_url, filename=data_file)\n\n # extract files\n with ZipFile(data_file, 'r') as zip:\n print('extracting files...')\n zip.extractall()\n print('finished extracting')\n data_dir = zip.namelist()[0]\n\n # delete zip file\n os.remove(data_file)\n return data_dir\n\n\ndef main():\n print(\"Torch version:\", torch.__version__)\n\n # get command-line arguments\n parser = argparse.ArgumentParser()\n parser.add_argument('--num_epochs', type=int, default=25,\n help='number of epochs to train')\n parser.add_argument('--output_dir', type=str, help='output directory')\n parser.add_argument('--learning_rate', type=float,\n default=0.001, help='learning rate')\n parser.add_argument('--momentum', type=float, default=0.9, help='momentum')\n args = parser.parse_args()\n\n data_dir = download_data()\n print(\"data directory is: \" + data_dir)\n model = fine_tune_model(args.num_epochs, data_dir,\n args.learning_rate, args.momentum)\n os.makedirs(args.output_dir, exist_ok=True)\n torch.save(model, os.path.join(args.output_dir, 'model.pt'))\n\n\nif __name__ == \"__main__\":\n main()", 138 | "execution_count": null, 139 | "outputs": [] 140 | }, 141 | { 142 | "metadata": {}, 143 | "cell_type": "markdown", 144 | "source": "### Azure MLの学習結果をログに保存\n\n上記のコードにはAzure MLの環境で学習を実行し、結果を追跡するにはいくつかのAzure MLコードが追記されています。 \n詳細は[こちらの公式のドキュメント](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-track-experiments)を確認してください。 \n今回記述されている内容をそれぞれ確認しましょう。 \n\n学習経過には`Azure ML Run`オブジェクトを使用することによってアクセスすることができます。 \n上記のコード内で設定を行なっている部分を確認しましょう。 \n\n```Python\nfrom azureml.core.run import Run\nrun = Run.get_context()\n```\n\nさらに`learning rate`、`momentum`のパラメータ、検証データに対する最高のAccuracy(正解率)のログも取得します。 \n\n```Python\nrun.log('lr', np.float(learning_rate))\nrun.log('momentum', np.float(momentum))\n\nrun.log('best_val_acc', np.float(best_acc))\n```\n\nハイパーパラメータの調整を行う際にこちらのログは重要な役割を果たします。 \nこちらのスクリプトを先ほど作成した、作業ディレクトリに保存しておきます。 " 145 | }, 146 | { 147 | "metadata": { 148 | "trusted": true 149 | }, 150 | "cell_type": "code", 151 | "source": "import shutil\n\nshutil.copy('pytorch_train.py', project_folder)", 152 | "execution_count": null, 153 | "outputs": [] 154 | }, 155 | { 156 | "metadata": {}, 157 | "cell_type": "markdown", 158 | "source": "### Experimentの作成\nワークスペースですべての実行結果を追跡するために[Experiment](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#experiment) を作成します。 " 159 | }, 160 | { 161 | "metadata": { 162 | "trusted": true 163 | }, 164 | "cell_type": "code", 165 | "source": "from azureml.core import Experiment\n\nexperiment_name = 'pytorch-hymenoptera'\nexperiment = Experiment(ws, name=experiment_name)", 166 | "execution_count": null, 167 | "outputs": [] 168 | }, 169 | { 170 | "metadata": {}, 171 | "cell_type": "markdown", 172 | "source": "### PyTorch estimatorの作成\n\nAzure ML SDK の PyTorch Estimator を使用すると、単一ノードと分散の両方の実行について、PyTorchトレーニングジョブを簡単に送信できます。 \nPyTorch Estimatorの詳細については、[こちら](https://docs.microsoft.com/azure/machine-learning/service/how-to-train-pytorch)を参照してください。次のコードは単一ノードの PyTorch ジョブを定義します。" 173 | }, 174 | { 175 | "metadata": { 176 | "trusted": true 177 | }, 178 | "cell_type": "code", 179 | "source": "from azureml.train.dnn import PyTorch\n\nscript_params = {\n '--num_epochs': 30,\n '--output_dir': './outputs'\n}\n\nestimator = PyTorch(source_directory=project_folder, \n script_params=script_params,\n compute_target=compute_target,\n entry_script='pytorch_train.py',\n use_gpu=True)", 180 | "execution_count": null, 181 | "outputs": [] 182 | }, 183 | { 184 | "metadata": {}, 185 | "cell_type": "markdown", 186 | "source": "`scripti_params`に訓練に必要な引数を渡す必要があります。  \n\n\n#### script_params\n\n`script_params`は` entry_script`で指定しているスクリプトに必要な引数を渡す辞書型のオブジェクトです。 \n今回の設定は下記になります。 \n- `--num_epochs`:`30`→エポック数を30に設定\n- `'--output_dir': './outputs'`→学習の実行履歴を保存するディレクトリの指定\n\nこの出力ディレクトリである `./ output`はAzure ML上で特別に扱われます。 \nこのディレクトリ内の情報は全て実行履歴の一部としてワークスペースにアップロードされ、リモート実行が終了してもアクセス可能です。\n\n#### データストアからデータの読み込み\n\n訓練時にデータを読み込む必要がある場合はデータストアと呼ばれる場所にデータをUploadし、そこからデータを読み込む必要があります。 \nその方法については[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-access-data)を確認してください。 \n(データストアはワークスペースのリソースを作成した段階で使用可能になります。) \n\n\n#### GPUの使用\n\nAzure VMのGPUをトレーニングに活用するには、`use_gpu = True`に設定します。\nCPUしか利用できない場合は、このパラメーターを削除するか、`user_gpu=False` に設定しなおします。\n\n各種パラメーター:\n[PyTorch class](https://docs.microsoft.com/ja-jp/python/api/azureml-train-core/azureml.train.dnn.pytorch?view=azure-ml-py)" 187 | }, 188 | { 189 | "metadata": { 190 | "slideshow": { 191 | "slide_type": "fragment" 192 | } 193 | }, 194 | "cell_type": "markdown", 195 | "source": "### ジョブの実行\n\nEstimatorオブジェクトを送信してExperimentを実行します。 \nこの実行は非同期です。\n\n学習の実行には下記の4ステップがあります。 \n\n1. 準備:Chainer Estimater で指定されたPython環境に合わせてdockerイメージが作成され、それがワークスペースのAzure Container Registryにアップロードされます。このステップはPython環境ごとに一度だけ起こります。(その後の実行のためにコンテナはキャッシュされます。)画像の作成とアップロードには約5分かかります。ジョブの準備中、ログは実行履歴にストリーミングされ、イメージ作成の進行状況を監視するために表示できます。\n\n2. スケーリング:計算をスケールアップする必要がある場合(つまり、バッチAIクラスターで現在実行可能な数より多くのノードを実行する必要がある場合)、クラスターは必要な数のノードを使用可能にするためにスケールアップを試みます。スケーリングは通常約5分かかります。\n\n3. 実行中:スクリプトフォルダ内のすべてのスクリプトがコンピューティングターゲットにアップロードされ、データストアがマウントまたはコピーされてentry_scriptが実行されます。ジョブの実行中は、stdoutと./logsフォルダが実行履歴にストリーミングされ、実行の進行状況を監視するために表示できます。\n\n4. 後処理:実行の./outputsフォルダが実行履歴にコピーされます。\n\n環境にもよりますが、20分程度かかります。" 196 | }, 197 | { 198 | "metadata": { 199 | "trusted": true 200 | }, 201 | "cell_type": "code", 202 | "source": "run = experiment.submit(estimator)\nprint(run)", 203 | "execution_count": null, 204 | "outputs": [] 205 | }, 206 | { 207 | "metadata": { 208 | "trusted": true 209 | }, 210 | "cell_type": "code", 211 | "source": "# to get more details of your run\nprint(run.get_details())", 212 | "execution_count": null, 213 | "outputs": [] 214 | }, 215 | { 216 | "metadata": {}, 217 | "cell_type": "markdown", 218 | "source": "### 実行経過の確認\n\nJupyter Notebookのウィジェットを使用して実行の進行状況を監視できます。 \n実行依頼と同様に、ウィジェットは非同期で、ジョブが完了するまで10〜15秒ごとにライブアップデートを行います。\n\nまた、このウィジェットの `Status` が `Queued` になると。実際にGPUマシンが自動的に作成されます。\n\nウィジェットの一番下にある `Click here to see the run in Azure portal` から、`コンピューティング` の状態も併せて確認してください。[最新の情報を更新] を押してリフレッシュすることをお勧めします。" 219 | }, 220 | { 221 | "metadata": { 222 | "trusted": true 223 | }, 224 | "cell_type": "code", 225 | "source": "from azureml.widgets import RunDetails\n\nRunDetails(run).show()", 226 | "execution_count": null, 227 | "outputs": [] 228 | }, 229 | { 230 | "metadata": {}, 231 | "cell_type": "markdown", 232 | "source": "また、スクリプトがトレーニングを完了するまでブロックしてから、学習結果を確認することも可能です。" 233 | }, 234 | { 235 | "metadata": { 236 | "trusted": true 237 | }, 238 | "cell_type": "code", 239 | "source": "run.wait_for_completion(show_output=True)", 240 | "execution_count": null, 241 | "outputs": [] 242 | }, 243 | { 244 | "metadata": {}, 245 | "cell_type": "markdown", 246 | "source": "## 学習済みモデルのデプロイ\n\n学習済みモデルが作成できました。 \n続いてそのモデルをAzureにデプロイします。 \n今回はモデルを[Azure Container Instances](https://docs.microsoft.com/en-us/azure/container-instances/)(ACI)にWebサービスとしてデプロイします。 \nAzure MLを使用してモデルを展開する方法の詳細については、[こちら](https://docs.microsoft.com/azure/machine-learning/service/how-to-deploy-and-where)を参照してください。" 247 | }, 248 | { 249 | "metadata": {}, 250 | "cell_type": "markdown", 251 | "source": "### 学習済みモデルの保存\n\n`run.register_model`を使用すると学習済みモデルを保存することが可能です。 " 252 | }, 253 | { 254 | "metadata": { 255 | "trusted": true 256 | }, 257 | "cell_type": "code", 258 | "source": "model = run.register_model(model_name='pytorch-hymenoptera', model_path='outputs/model.pt')\nprint(model.name, model.id, model.version, sep = '\\t')", 259 | "execution_count": null, 260 | "outputs": [] 261 | }, 262 | { 263 | "metadata": {}, 264 | "cell_type": "markdown", 265 | "source": "### スコアリングスクリプトの作成\n\nまず、Webサービスに呼び出されるスコアリングスクリプトを作成します。 \nスコアリングスクリプトには、2つの関数が必要になります。\n\n- `init()`:この関数では、通常モデルを `global`オブジェクトにロードします。この関数はDockerコンテナが起動されたときに一度だけ実行されます。\n- `run(input_data)`:この関数では、新たな入力データ対して学習済みモデルを使用して推論を実行します。通常は入力と出力は通常シリアライゼーションとデシリアライゼーションのフォーマットとしてJSONを使用しますが、他のフォーマットも使用することが可能です。\n\n今回は準備されている`pytorch_score.py`を使用します。 \nまた用意されているテスト用の画像ファイルを使用して推論を実行します。 \n独自のスコアリングスクリプトを書くときは、Webサービスを実行する前にまずローカルでテストすることを忘れないでください。 \n\n使用するスクリプトは下記になります。 " 266 | }, 267 | { 268 | "metadata": { 269 | "trusted": true 270 | }, 271 | "cell_type": "code", 272 | "source": "%%writefile pytorch_score.py\n\nimport torch\nimport torch.nn as nn\nfrom torchvision import transforms\nimport json\n\nfrom azureml.core.model import Model\n\n\ndef init():\n global model\n model_path = Model.get_model_path('pytorch-hymenoptera')\n model = torch.load(model_path, map_location=lambda storage, loc: storage)\n model.eval()\n\n\ndef run(input_data):\n input_data = torch.tensor(json.loads(input_data)['data'])\n\n # get prediction\n with torch.no_grad():\n output = model(input_data)\n classes = ['ants', 'bees']\n softmax = nn.Softmax(dim=1)\n pred_probs = softmax(output).numpy()[0]\n index = torch.argmax(output, 1)\n\n result = {\"label\": classes[index], \"probability\": str(pred_probs[index])}\n return result", 273 | "execution_count": null, 274 | "outputs": [] 275 | }, 276 | { 277 | "metadata": {}, 278 | "cell_type": "markdown", 279 | "source": "### 環境ファイルを作成する\n\nスコアリングスクリプトのすべてのパッケージ依存関係を指定する環境ファイル( `myenv.yml`)を作成する必要があります。このファイルは、Azure MLによってこれらのすべての依存関係がDockerイメージにインストールされるようにするために使用されます。この場合、 `azureml-core`、` torch`、そして `torchvision`が必要になります。" 280 | }, 281 | { 282 | "metadata": { 283 | "trusted": true 284 | }, 285 | "cell_type": "code", 286 | "source": "from azureml.core.conda_dependencies import CondaDependencies \n\nmyenv = CondaDependencies.create(pip_packages=['azureml-defaults', 'torch', 'torchvision'])\n\nwith open(\"myenv.yml\",\"w\") as f:\n f.write(myenv.serialize_to_string())\n \nprint(myenv.serialize_to_string())", 287 | "execution_count": null, 288 | "outputs": [] 289 | }, 290 | { 291 | "metadata": {}, 292 | "cell_type": "markdown", 293 | "source": "### Dockerイメージの設定\n\nACIコンテナーを構築するために使用するDockerイメージを構成します。 \n詳細については[こちらの公式ドキュメント](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.image.containerimage?view=azure-ml-py)を確認してください。 \n\n併せて Azure Portal の `イメージ` で、指定したコンテナーイメージが作成されているもの確認してください。" 294 | }, 295 | { 296 | "metadata": { 297 | "trusted": true 298 | }, 299 | "cell_type": "code", 300 | "source": "from azureml.core.image import ContainerImage\n\nimage_config = ContainerImage.image_configuration(execution_script='pytorch_score.py', \n runtime='python', \n conda_file='myenv.yml',\n description='Image with hymenoptera model')", 301 | "execution_count": null, 302 | "outputs": [] 303 | }, 304 | { 305 | "metadata": {}, 306 | "cell_type": "markdown", 307 | "source": "### ACIコンテナの設定\n\nデプロイのための準備がほぼ整いました。 \nACIコンテナに必要なCPUの数とギガバイトのRAMを指定するためのデプロイメント構成ファイルを作成します。 \nそれは作成したモデルに依存しますが、一般的なモデルではデフォルトの `1`コアと` 1`ギガバイトのRAMで十分なケースが多いです。 " 308 | }, 309 | { 310 | "metadata": { 311 | "trusted": true 312 | }, 313 | "cell_type": "code", 314 | "source": "from azureml.core.webservice import AciWebservice\n\naciconfig = AciWebservice.deploy_configuration(cpu_cores=1, \n memory_gb=1, \n tags={'data': 'hymenoptera', 'method':'transfer learning', 'framework':'pytorch'},\n description='Classify ants/bees using transfer learning with PyTorch')", 315 | "execution_count": null, 316 | "outputs": [] 317 | }, 318 | { 319 | "metadata": {}, 320 | "cell_type": "markdown", 321 | "source": "### Container Instances にデプロイする\n\n最後に、登録したモデルからWebサービスをデプロイしましょう。 \n前の手順で作成したACI設定ファイルとイメージ設定ファイルを使用してWebサービスをデプロイします。 \n\nリストの中の `model`オブジェクトを` models`パラメータに渡します。 \n複数の登録済みモデルをデプロイする場合は、このリストに他のモデルを追加してください。  " 322 | }, 323 | { 324 | "metadata": { 325 | "trusted": true 326 | }, 327 | "cell_type": "code", 328 | "source": "%%time\nfrom azureml.core.webservice import Webservice\n\nservice_name = 'aci-hymenoptera'\nservice = Webservice.deploy_from_model(workspace=ws,\n name=service_name,\n models=[model],\n image_config=image_config,\n deployment_config=aciconfig,)\n\nservice.wait_for_deployment(show_output=True)\nprint(service.state)", 329 | "execution_count": null, 330 | "outputs": [] 331 | }, 332 | { 333 | "metadata": {}, 334 | "cell_type": "markdown", 335 | "source": "通常デプロイには7~8分かかります。 \n下記のように表示されればデプロイが成功しています。 \n\n```\nSucceededACI service creation operation finished, operation \"Succeeded\"\n\n```\n\n#### デプロイがうまくいかない場合\n\nもし、何らかの理由でデプロイが失敗して再デプロイする必要がある場合は、必ずサービスを`service.delete()`で削除してください。一番下のセルにあります。\n\n**また、デプロイに問題が発生した場合、まず下記のコマンドを実行して、サービスからログを取得しましょう。**" 336 | }, 337 | { 338 | "metadata": { 339 | "trusted": true 340 | }, 341 | "cell_type": "code", 342 | "source": "service.get_logs()", 343 | "execution_count": null, 344 | "outputs": [] 345 | }, 346 | { 347 | "metadata": {}, 348 | "cell_type": "markdown", 349 | "source": "RESTクライアント呼び出しを受け付けるWebサービスのHTTPエンドポイントを取得します。 \nこのエンドポイントは、Webサービスをテストしたい、またはそれをアプリケーションに統合したい人と共有することができます。" 350 | }, 351 | { 352 | "metadata": { 353 | "trusted": true 354 | }, 355 | "cell_type": "code", 356 | "source": "print(service.scoring_uri)", 357 | "execution_count": null, 358 | "outputs": [] 359 | }, 360 | { 361 | "metadata": {}, 362 | "cell_type": "markdown", 363 | "source": "## デプロイされたサービスをテストする\n\n最後に、デプロイしたWebサービスをテストしましょう。 \nデータをJSON文字列としてACIでホストされているWebサービスに送信し、SDKの `run` APIを使用してサービスを呼び出します。 \nここで、検証データからイメージを取得して推論を実行します。" 364 | }, 365 | { 366 | "metadata": { 367 | "trusted": true 368 | }, 369 | "cell_type": "code", 370 | "source": "import os, json\nfrom PIL import Image\nimport matplotlib.pyplot as plt\n\nplt.imshow(Image.open('./data/test_img.jpg'))", 371 | "execution_count": null, 372 | "outputs": [] 373 | }, 374 | { 375 | "metadata": {}, 376 | "cell_type": "markdown", 377 | "source": "画像データに対して学習時と同じ前処理を適応し、推論が実行できる状態に変更します。 " 378 | }, 379 | { 380 | "metadata": { 381 | "trusted": true 382 | }, 383 | "cell_type": "code", 384 | "source": "import torch\nfrom torchvision import transforms\n \ndef preprocess(image_file):\n \"\"\"Preprocess the input image.\"\"\"\n data_transforms = transforms.Compose([\n transforms.Resize(256),\n transforms.CenterCrop(224),\n transforms.ToTensor(),\n transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n ])\n\n image = Image.open(image_file)\n image = data_transforms(image).float()\n image = torch.tensor(image)\n image = image.unsqueeze(0)\n return image.numpy()", 385 | "execution_count": null, 386 | "outputs": [] 387 | }, 388 | { 389 | "metadata": {}, 390 | "cell_type": "markdown", 391 | "source": "デプロイしたAPIを使用して推論を実行します。 " 392 | }, 393 | { 394 | "metadata": { 395 | "trusted": true 396 | }, 397 | "cell_type": "code", 398 | "source": "input_data = preprocess('./data/test_img.jpg')\nresult = service.run(input_data=json.dumps({'data': input_data.tolist()}))\nprint(result)", 399 | "execution_count": null, 400 | "outputs": [] 401 | }, 402 | { 403 | "metadata": {}, 404 | "cell_type": "markdown", 405 | "source": "うまく推論ができていることが確認できました。 \nこのデプロイされたモデルに関してはAzure Portalの「デプロイ」タブから詳細情報について確認することができます。 \n\nこれでAzure Machine Learningの基礎的な使用方法が理解できました。 " 406 | }, 407 | { 408 | "metadata": {}, 409 | "cell_type": "markdown", 410 | "source": "## 後片付け\n\nWebサービスが不要になったら、API呼び出しで簡単に削除できます。" 411 | }, 412 | { 413 | "metadata": { 414 | "trusted": true 415 | }, 416 | "cell_type": "code", 417 | "source": "service.delete()", 418 | "execution_count": null, 419 | "outputs": [] 420 | }, 421 | { 422 | "metadata": {}, 423 | "cell_type": "markdown", 424 | "source": "続いては一緒に手持ちのデータを使用して学習を行う方法を確認します。 \nまた今回は行わなかったハイパーパラメータの調整方法もご紹介します。 " 425 | } 426 | ], 427 | "metadata": { 428 | "authors": [ 429 | { 430 | "name": "minxia" 431 | } 432 | ], 433 | "kernelspec": { 434 | "name": "python36", 435 | "display_name": "Python 3.6", 436 | "language": "python" 437 | }, 438 | "language_info": { 439 | "mimetype": "text/x-python", 440 | "nbconvert_exporter": "python", 441 | "name": "python", 442 | "pygments_lexer": "ipython3", 443 | "version": "3.6.6", 444 | "file_extension": ".py", 445 | "codemirror_mode": { 446 | "version": 3, 447 | "name": "ipython" 448 | } 449 | }, 450 | "msauthor": "minxia" 451 | }, 452 | "nbformat": 4, 453 | "nbformat_minor": 2 454 | } -------------------------------------------------------------------------------- /02.train-hyperparametertune-deploy_chainer.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "metadata": { 5 | "collapsed": true 6 | }, 7 | "cell_type": "markdown", 8 | "source": "# [Chainer] Azure MLで、自分のファイルを使って、ハイパーパラメーターの調整まで\n\n先ほどの解説では用意されてものを使用してきました。 \nこのハンズオンでは自身のデータを用いて、ハンズオン終了後にもAzure MLを使いこなすようになることを目指します。 また、Chainer を使用して学習を行います。\n\nこのハンズオンでは下記の内容を行います。 \n- モデルのトレーニング\n- ハイパーパラメーターの調整\n- (開発途中)デプロイ" 9 | }, 10 | { 11 | "metadata": { 12 | "trusted": true 13 | }, 14 | "cell_type": "code", 15 | "source": "import azureml.core\n\nprint(\"This notebook was created using version 1.0.15 of the Azure ML SDK\")\nprint(\"You are currently using version\", azureml.core.VERSION, \"of the Azure ML SDK\")", 16 | "execution_count": null, 17 | "outputs": [] 18 | }, 19 | { 20 | "metadata": { 21 | "collapsed": true 22 | }, 23 | "cell_type": "markdown", 24 | "source": "ここでは、Python SDK の Chainer Estimator を使います。Chainer Estimator は SDK の **1.0.15** から導入されています。\n\nAzure Notebook の Azure Machine Learning Serivice SDK のバージョンが 1.0.15よりも古い場合は、以下のコマンドで最新版にアップデートしてください。" 25 | }, 26 | { 27 | "metadata": { 28 | "trusted": true 29 | }, 30 | "cell_type": "code", 31 | "source": "!pip install --upgrade azureml-sdk[notebooks,automl] azureml-dataprep", 32 | "execution_count": null, 33 | "outputs": [] 34 | }, 35 | { 36 | "metadata": {}, 37 | "cell_type": "markdown", 38 | "source": "## Azure Machine Services の Workspace へのログインと接続\n\nAzure Machine Learning service へ接続を行います。アクセス権設定は、Azure Machine Learning services 作成時に自動的に行われています。作成した方はもちろん、その Workspace へアクセスできます。\n\nAzure Notebook からは、シングルサインオンができます。以下のセルを実行すると、ログイン用のダイアログが表示されます。そのままログインをして先に進んでください。" 39 | }, 40 | { 41 | "metadata": { 42 | "trusted": true 43 | }, 44 | "cell_type": "code", 45 | "source": "from azureml.core.workspace import Workspace\n\nws = Workspace.from_config()\nprint('Workspace name: ' + ws.name, \n 'Azure region: ' + ws.location, \n 'Resource group: ' + ws.resource_group, sep = '\\n')", 46 | "execution_count": null, 47 | "outputs": [] 48 | }, 49 | { 50 | "metadata": {}, 51 | "cell_type": "markdown", 52 | "source": "## コンピューティング ターゲットの設定\n\n[コンピューティングターゲット](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#compute-target)を作成する必要があります。このチュートリアルではAzure ML managed compute ([AmlCompute](https://docs.microsoft.com/azure/machine-learning/service/how-to-set-up-training-targets#amlcompute))を使用します。 \n(コンピューティングターゲットは計算を実行する場所を決定するようなイメージです。)\n\n※AmlComputeの作成には約5分かかります。 \nその名前のAmlComputeが既にワークスペースにある場合、このコードは作成プロセスをスキップします。\n\n他のAzureサービスと同様に、Azure Machine Learningサービスに関連する特定のリソース(AmlComputeなど)には制限があります。 \nデフォルトの制限と、より多くのクォータを要求する方法についての[この記事](https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-manage-quotas)を読んでください。" 53 | }, 54 | { 55 | "metadata": { 56 | "trusted": true 57 | }, 58 | "cell_type": "code", 59 | "source": "from azureml.core.compute import ComputeTarget, AmlCompute\nfrom azureml.core.compute_target import ComputeTargetException\n\n# choose a name for your cluster\ncluster_name = \"gpucluster\"\n\ntry:\n compute_target = ComputeTarget(workspace=ws, name=cluster_name)\n print('Found existing compute target.')\nexcept ComputeTargetException:\n print('Creating a new compute target...')\n compute_config = AmlCompute.provisioning_configuration(vm_size=\"Standard_NC6\", ## Standard_NC6s_v3\n min_nodes=1,\n max_nodes=1,\n vm_priority='lowpriority') ## vm_priority='lowpriority' | `dedicated'\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 the 'status' property to get a detailed status for the current cluster. \nprint(compute_target.status.serialize())", 60 | "execution_count": null, 61 | "outputs": [] 62 | }, 63 | { 64 | "metadata": {}, 65 | "cell_type": "markdown", 66 | "source": "# (Option) Data Science VM の設定\n\n**AmlCompute の作成ができた方は **スキップ** してください!!!実行すると、AmlCompute設定が**上書き**されてしまいます。**\n\nAzure Machine Learning Services では、Data Science VMのGPUインスタンス版など、リモートの仮想マシンを学習の実行環境に設定することもできます。\n\nAzure 無償トライアルなどで、GPUインスタンスのクォータ引き上げが出来ない場合もありますのでご注意ください。\n\n[こちら](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-set-up-training-targets#vm) のドキュメントを参照して、*事前*に Data Science VM を作成してから、以下を実行してください。" 67 | }, 68 | { 69 | "metadata": { 70 | "trusted": true 71 | }, 72 | "cell_type": "code", 73 | "source": "from azureml.core.compute import RemoteCompute, ComputeTarget\n\n# Create the compute config \ncompute_target_name = 'attachdsvm'\nattach_config = RemoteCompute.attach_configuration(address='',\n ssh_port=22,\n username='User Name',\n password='Password')\n\n# Attach the compute\ncompute_target = ComputeTarget.attach(ws, compute_target_name, attach_config)\n\ncompute_target.wait_for_completion(show_output=True)", 74 | "execution_count": null, 75 | "outputs": [] 76 | }, 77 | { 78 | "metadata": {}, 79 | "cell_type": "markdown", 80 | "source": "## データストアにデータをUpload\n\nリモートコンピューティングクラスタを使用して学習する準備が整いました。 \nまずは学習用のデータを準備します。 \n今回は手持ちのデータを使用するため、データを[データストア](https://docs.microsoft.com/azure/machine-learning/service/how-to-access-data)にUploadする必要があります。 \nデータストアは、データを格納できる場所であり、データをマウントするか、計算対象にデータをコピーすることによってRunにアクセスできるようになります。 \nデータストアは、Azure Blob StorageまたはAzure File Shareのいずれかでバックアップできます(ADLSは将来サポートされる予定です)。 \n単純なデータ処理のために、データがまだBlob StorageまたはFile Shareにない場合は、各ワークスペースに使用可能なデフォルトのデータストアが用意されています。\n\n### プロジェクトディレクトリの作成\n\n学習実行に必要なコードを格納するディレクトリを作成します。 \nこのディレクトリには学習を実行するコードと、それに依存関係のファイルなどを格納するする必要があります。 " 81 | }, 82 | { 83 | "metadata": { 84 | "trusted": true 85 | }, 86 | "cell_type": "code", 87 | "source": "import os\n\nproject_folder = './chainer-doc_cat'\nos.makedirs(project_folder, exist_ok=True)", 88 | "execution_count": null, 89 | "outputs": [] 90 | }, 91 | { 92 | "metadata": {}, 93 | "cell_type": "markdown", 94 | "source": "今回は`chainer-doc_cat`という名前のプロジェクトフォルダを作成しました。 " 95 | }, 96 | { 97 | "metadata": {}, 98 | "cell_type": "markdown", 99 | "source": "### データストアの準備\n\n今回の問題設定は犬と猫の分類です。 \n先ほどはWeb上に準備されたデータを取得して学習を行いましたが、今回は自身のデータを使用することを想定して学習を行います。 \n今回はデフォルトで設定されているデータストアを使用します。 \n\nGithub からクローンした際に、`/data/doc_cat` フォルダーに、学習用のデータセットも一緒にコピーしています。" 100 | }, 101 | { 102 | "metadata": { 103 | "trusted": true 104 | }, 105 | "cell_type": "code", 106 | "source": "datastores = ws.datastores\nfor name, dss in datastores.items():\n print(name, dss.datastore_type)\n \nds = ws.get_default_datastore()\nprint(ds.name, ds.datastore_type, ds.account_name, ds.container_name)", 107 | "execution_count": null, 108 | "outputs": [] 109 | }, 110 | { 111 | "metadata": {}, 112 | "cell_type": "markdown", 113 | "source": "この次のステップでは、トレーニングとテストセットをワークスペースのデフォルトデータストアにアップロードします。 \nこれは後で`AmlCompute`クラスターにマウントしてトレーニングを行います。" 114 | }, 115 | { 116 | "metadata": { 117 | "trusted": true 118 | }, 119 | "cell_type": "code", 120 | "source": "%%time\nds.upload(src_dir='./data', target_path='data', overwrite=True, show_progress=True)", 121 | "execution_count": null, 122 | "outputs": [] 123 | }, 124 | { 125 | "metadata": {}, 126 | "cell_type": "markdown", 127 | "source": "## 学習スクリプトの作成\n\n基本的には先ほど使用したものを用います。 \nデータの読み込みの部分が持っているデータを扱うため、データをダウンロードする必要がなくなります。 \n\nスクリプトは下記のディレクトリに格納しておきます。 " 128 | }, 129 | { 130 | "metadata": { 131 | "trusted": true 132 | }, 133 | "cell_type": "code", 134 | "source": "%%writefile chainer-doc_cat/train.py\n\nimport numpy as np\nimport chainer\nimport chainer.links as L\nimport chainer.functions as F\nimport cupy\nfrom glob import glob\nfrom chainer.datasets import TransformDataset\nfrom zipfile import ZipFile\nimport time\nimport os\nimport copy\nimport argparse\nimport random\nfrom model import GoogleNet\n\nimport chainermn\n\nfrom azureml.core.run import Run\n# get the Azure ML run object\nrun = Run.get_context()\n\n# データの読み込み関数\ndef get_data(data_folder):\n data_file = os.path.join(data_folder, 'data/dog-cat.zip')\n# data_file = data_folder\n \n print('training dataset is stored here:', data_file)\n\n # extract files\n with ZipFile(data_file, 'r') as zipfile:\n try:\n print('extracting files...')\n zipfile.extractall()\n print('finished extracting')\n data_dir = zipfile.namelist()[0]\n except:\n data_dir = zipfile.namelist()[0]\n\n return data_dir\n\n# データに対する前処理用の関数\ndef transform(inputs):\n img, label = inputs\n img = img.transpose(1,2,0)\n img = L.model.vision.googlenet.prepare(img)\n img, label = cupy.asarray(img), cupy.asarray(label)\n return img, label\n\n# データセットの作成と前処理の適応\ndef prepare_data(data_dir):\n labels = {'dog':0, 'cat':1}\n # パスの取得\n train_dog = [(path, labels['dog']) for path in glob('{}{}/{}/*'.format(data_dir, 'train','dog'))]\n train_cat = [(path, labels['cat']) for path in glob('{}{}/{}/*'.format(data_dir, 'train','cat'))]\n val_dog = [(path, labels['dog']) for path in glob('{}{}/{}/*'.format(data_dir, 'val','dog'))]\n val_cat = [(path, labels['cat']) for path in glob('{}{}/{}/*'.format(data_dir, 'val','cat'))]\n # データセットの作成\n train = chainer.datasets.LabeledImageDataset(train_dog+train_cat)\n valid= chainer.datasets.LabeledImageDataset(val_dog+val_cat)\n # 前処理の適応\n train = TransformDataset(train, transform)\n valid = TransformDataset(valid, transform)\n\n return train, valid\n\n# 乱数のシード固定用の関数\ndef reset_seed(seed=0):\n random.seed(seed)\n np.random.seed(seed)\n if chainer.cuda.available:\n chainer.cuda.cupy.random.seed(seed)\n\n# 学習用の関数\ndef train_model(model, comm, optimizer, data_dir, batchsize, num_epochs, learning_rate, lr_shift_timing, lr_shift_rate):\n train, valid = prepare_data(data_dir)\n train = chainermn.scatter_dataset(train, comm, shuffle=True)\n valid = chainermn.scatter_dataset(valid, comm, shuffle=True)\n # Iteratorの定義\n train_iter = chainer.iterators.SerialIterator(train, batchsize)\n valid_iter = chainer.iterators.SerialIterator(valid, batchsize, repeat=False, shuffle=False)\n train_iter.reset()\n valid_iter.reset()\n best_accuracy = 0\n print(\"starting training\")\n\n # 学習ループの実行\n while train_iter.epoch < num_epochs:\n\n # ------------ 学習の1イテレーション ------------\n\n # データの取得\n train_batch = train_iter.next()\n x_train, t_train = chainer.dataset.concat_examples(train_batch)\n\n # 予測値の計算\n y_train = model(x_train)\n\n # ロスの計算\n loss_train = F.softmax_cross_entropy(y_train, t_train)\n\n # 勾配の計算\n model.cleargrads()\n loss_train.backward()\n\n # パラメータの更新\n optimizer.update()\n\n # 検証データで精度を計算\n accuracy_train = F.accuracy(y_train, t_train)\n accuracy_train = float(accuracy_train.data)\n\n # ---------------- ここまで ----------------\n\n if train_iter.is_new_epoch: # 新しいエポックに入った時のみ計算\n\n valid_accuracies, valid_losses = [], []\n while True:\n # 検証データの取得\n valid_batch = valid_iter.next()\n x_valid, t_valid = chainer.dataset.concat_examples(valid_batch)\n\n # 検証用データで順伝播の計算を実行\n with chainer.using_config('train', False), chainer.using_config('enable_backprop', False):\n y_valid = model(x_valid)\n\n # 検証データで損失関数を計算\n loss_valid = F.softmax_cross_entropy(y_valid, t_valid)\n valid_losses.append(float(loss_valid.data))\n\n # 検証データで精度を計算\n accuracy_valid = F.accuracy(y_valid, t_valid)\n valid_accuracies.append(float(accuracy_valid.data))\n\n if valid_iter.is_new_epoch: # 追加:1エポック計算し終わると、イテレーターをリセット\n valid_iter.reset()\n break\n\n # Exponentialの適応\n if (train_iter.epoch) % lr_shift_timing == 0:\n try:\n optimizer.alpha = optimizer.alpha * lr_shift_rate\n print(optimizer.alpha)\n except:\n optimizer.lr = optimizer.lr * lr_shift_rate\n print(optimizer.lr)\n \n # 結果を表示\n run.log('best_val_acc', np.mean(valid_accuracies))\n print('valid_loss:{:.04f} valid_accuracy:{:.04f}'.format(np.mean(valid_losses), np.mean(valid_accuracies)))\n print('---')\n \n return model\n\n# 学習を実行する関数\ndef fine_tune_model(device, comm, num_epochs, data_dir, learning_rate, optimizer_name, batchsize, lr_shift_timing, lr_shift_rate):\n # ハイパーパラメータの観測\n run.log('lr', np.float(learning_rate))\n run.log('opt_name', str(optimizer_name))\n run.log('batchsize', int(batchsize))\n\n # インスタンス化\n reset_seed(0)\n model = GoogleNet()\n if device >= 0:\n chainer.cuda.get_device_from_id(device).use()\n model.to_gpu(device)\n print(\"1, passed the model to gpu\")\n else:\n print(\"2, didn't passe the model to gpu\")\n # Optimizerの定義とmodelとの紐づけ\n if 'SGD' == optimizer_name:\n optimizer = chainer.optimizers.SGD(lr=learning_rate)\n elif 'MomentumSGD' == optimizer_name:\n optimizer = chainer.optimizers.MomentumSGD(lr=learning_rate)\n else:\n optimizer = chainer.optimizers.Adam(alpha=learning_rate)\n optimizer = chainermn.create_multi_node_optimizer(optimizer, comm).setup(model)\n model.base.disable_update() # 学習済みモデル部分の学習を行わない\n # 学習の実行\n model = train_model(model, comm, optimizer, data_dir, batchsize, num_epochs, learning_rate, lr_shift_timing, lr_shift_rate)\n return model\n\ndef main():\n print(\"Chainer version:\", chainer.__version__)\n\n # get command-line arguments\n parser = argparse.ArgumentParser()\n parser.add_argument('--data_folder', type=str, dest='data_folder', help='data folder mounting point')\n parser.add_argument('--num_epochs', type=int, default=20,help='number of epochs to train')\n parser.add_argument('--output_dir', type=str, help='output directory')\n parser.add_argument('--communicator', type=str, default='hierarchical', help='Type of communicator')\n parser.add_argument('--learning_rate', type=float,default=0.01, help='learning rate')\n parser.add_argument('--optimizer_name', type=str,default='SGD', help='name of optimizer')\n parser.add_argument('--batchsize', type=int, default=64, help='batchsize')\n parser.add_argument('--lr_shift_timing', type=int, default=6, help='Exponential shigt timing by epoch')\n parser.add_argument('--lr_shift_rate', type=float, default=0.01, help='Exponential shigt ratio by epoch')\n args = parser.parse_args()\n \n comm = chainermn.create_communicator(args.communicator)\n device = comm.intra_rank\n print(\"communicator is {}, device is{}\".format(comm, device))\n \n print(\" insidedata_folder: \" + args.data_folder)\n data_dir = get_data(args.data_folder)\n print(\"data directory is: \" + data_dir)\n model = fine_tune_model(device, comm, args.num_epochs, data_dir, args.learning_rate, args.optimizer_name, args.batchsize, args.lr_shift_timing, args.lr_shift_rate)\n os.makedirs(args.output_dir, exist_ok=True)\n model.to_cpu()\n chainer.serializers.save_npz(os.path.join(args.output_dir, 'model.npz'), model)\n\nif __name__ == \"__main__\":\n main()", 135 | "execution_count": null, 136 | "outputs": [] 137 | }, 138 | { 139 | "metadata": {}, 140 | "cell_type": "markdown", 141 | "source": "モデルを定義したスクリプトを準備しておきます。 " 142 | }, 143 | { 144 | "metadata": { 145 | "trusted": true 146 | }, 147 | "cell_type": "code", 148 | "source": "%%writefile chainer-doc_cat/model.py\n\nimport numpy as np\nimport chainer\nimport chainer.links as L\nimport chainer.functions as F\n\nclass GoogleNet(chainer.Chain):\n\n def __init__(self, n_out=2):\n super(GoogleNet, self).__init__()\n with self.init_scope():\n self.base = L.GoogLeNet()\n self.fc = L.Linear(None, n_out)\n\n def forward(self, x):\n h = self.base(x, layers=['pool5'])\n h = self.fc(h['pool5'])\n return h", 149 | "execution_count": null, 150 | "outputs": [] 151 | }, 152 | { 153 | "metadata": {}, 154 | "cell_type": "markdown", 155 | "source": "### Experimentの作成\nワークスペースですべての実行結果を追跡するために[Experiment](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#experiment) を作成します。 " 156 | }, 157 | { 158 | "metadata": { 159 | "trusted": true 160 | }, 161 | "cell_type": "code", 162 | "source": "from azureml.core import Experiment\n\nexperiment_name = 'chainer-dog-cat'\nexperiment = Experiment(ws, name=experiment_name)", 163 | "execution_count": null, 164 | "outputs": [] 165 | }, 166 | { 167 | "metadata": {}, 168 | "cell_type": "markdown", 169 | "source": "## Chainer estimatorの作成\n\nAzure ML SDKの Chainer estimatorを使用すると、単一ノードと分散の両方の実行について、Chainerトレーニングジョブを簡単に送信できます。 \nChainer estimatorの詳細については、[こちら](https://docs.microsoft.com/ja-jp/python/api/azureml-train-core/azureml.train.dnn.chainer?view=azure-ml-py)を参照してください。次のコードは単一ノードのChainerジョブを定義します。\n\nまた、DataStore を学習スクリプトからアクセスさせるための詳細については[こちら](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-access-data)を参照してください。\n\n先ほどの PyTouch の Estimater を呼び出すコードと、ほとんど差がない点を確認します。" 170 | }, 171 | { 172 | "metadata": { 173 | "trusted": true 174 | }, 175 | "cell_type": "code", 176 | "source": "from azureml.train.estimator import *\nfrom azureml.train.dnn import *\n\nscript_params = {\n '--data_folder': ds.as_mount(),\n '--num_epochs': 25,\n '--output_dir': './outputs',\n '--communicator': 'non_cuda_aware'\n}\n\nestimator = Chainer(source_directory=project_folder,\n compute_target=compute_target,\n script_params=script_params,\n entry_script='train.py',\n distributed_backend='mpi', \n pip_packages=['cupy-cuda90', 'mpi4py', 'cython', 'chainer==5.1', 'chainermn', 'chainercv'],\n use_gpu=True)", 177 | "execution_count": null, 178 | "outputs": [] 179 | }, 180 | { 181 | "metadata": {}, 182 | "cell_type": "markdown", 183 | "source": "## 学習の実行\n\n下記のコードで学習を実行します。" 184 | }, 185 | { 186 | "metadata": { 187 | "trusted": true 188 | }, 189 | "cell_type": "code", 190 | "source": "run = experiment.submit(estimator)\nprint(run)", 191 | "execution_count": null, 192 | "outputs": [] 193 | }, 194 | { 195 | "metadata": {}, 196 | "cell_type": "markdown", 197 | "source": "### 学習の経過の確認\n\n学習の実行には下記の4ステップがあります。 \n\n1. 準備:Chainer Estimater で指定されたPython環境に合わせてdockerイメージが作成され、それがワークスペースのAzure Container Registryにアップロードされます。このステップはPython環境ごとに一度だけ起こります。(その後の実行のためにコンテナはキャッシュされます。)画像の作成とアップロードには約5分かかります。ジョブの準備中、ログは実行履歴にストリーミングされ、イメージ作成の進行状況を監視するために表示できます。\n\n2. スケーリング:計算をスケールアップする必要がある場合(つまり、バッチAIクラスターで現在実行可能な数より多くのノードを実行する必要がある場合)、クラスターは必要な数のノードを使用可能にするためにスケールアップを試みます。スケーリングは通常約5分かかります。\n\n3. 実行中:スクリプトフォルダ内のすべてのスクリプトがコンピューティングターゲットにアップロードされ、データストアがマウントまたはコピーされてentry_scriptが実行されます。ジョブの実行中は、stdoutと./logsフォルダが実行履歴にストリーミングされ、実行の進行状況を監視するために表示できます。\n\n4. 後処理:実行の./outputsフォルダが実行履歴にコピーされます。" 198 | }, 199 | { 200 | "metadata": { 201 | "scrolled": true, 202 | "trusted": true 203 | }, 204 | "cell_type": "code", 205 | "source": "# to get more details of your run\nprint(run.get_details())", 206 | "execution_count": null, 207 | "outputs": [] 208 | }, 209 | { 210 | "metadata": { 211 | "scrolled": false, 212 | "trusted": true 213 | }, 214 | "cell_type": "code", 215 | "source": "from azureml.widgets import RunDetails\n\nRunDetails(run).show()", 216 | "execution_count": null, 217 | "outputs": [] 218 | }, 219 | { 220 | "metadata": { 221 | "trusted": true 222 | }, 223 | "cell_type": "code", 224 | "source": "run.wait_for_completion(show_output=True)", 225 | "execution_count": null, 226 | "outputs": [] 227 | }, 228 | { 229 | "metadata": {}, 230 | "cell_type": "markdown", 231 | "source": "手持ちのデータを用いて学習を実行することができました。 \nですが、現在はGPUマシンを1台立てて、学習を行っただけです。 \n\n続いてはGPUマシンを複数使用して、ハイパーパラメータの自動チューニングを確認します。 " 232 | }, 233 | { 234 | "metadata": {}, 235 | "cell_type": "markdown", 236 | "source": "## ハイパーパラメーターのチューニング\n\n基本的に必要な設定は下記になります。 \n\n- ハイパーパラメータを探索する範囲を選択\n- ハイパーパラメータを探索する方法を選択(ランダムスイープ、グリッドサーチ、ベイズ最適化)\n- 最大化or最小化したいメトリックの指定\n\n詳細の設定方法については[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-tune-hyperparameters)を確認してください。 \n\n\n### 学習率の調整\n\nトレーニングスクリプト(`train.py`)は数エポックごとに学習率を減少させるために学習率スケジュールを使うので、最初の学習率とmomentumのパラメータを調整しましょう。 \n今回はランダムスイープを使用します。 \n(この節でてくる語句については[公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-access-data)を確認してください。)\n" 237 | }, 238 | { 239 | "metadata": { 240 | "trusted": true 241 | }, 242 | "cell_type": "code", 243 | "source": "from azureml.train.hyperdrive import *\n\nparam_sampling = RandomParameterSampling( {\n 'learning_rate':uniform(0.005, 0.01),\n 'optimizer_name': choice('SGD', 'MomentumSGD', 'Adam'),\n 'batchsize': choice(16, 32, 64),\n }\n)", 244 | "execution_count": null, 245 | "outputs": [] 246 | }, 247 | { 248 | "metadata": {}, 249 | "cell_type": "markdown", 250 | "source": "### 早期終了(Early Stopping)の適応\n\n次に、パフォーマンスの低い実行を早期終了するための設定を行います。 \n\nここでは `BanditPolicy`を使います。これは主要なすべての実行を終了します。 \n設定はシンプルに3つの要素を指定します。\n\n- slack_factor:早期終了を行う閾値(指定したメトリックの最高のものとの誤差)\n- evaluation_interval:早期終了を確認する周期(エポック数)\n- delay_evaluation:早期終了を確認を始めるタイミング(0エポック目から何エポック遅らせるか)\n\nここでは、ポリシーをエポックごとに適用します(エポックごとに `best_val_acc`メトリックをレポートし、` evaluation_interval = 1`になるため) \n最初の `10`エポック(` delay_evaluation = 10`)の後まで最初のポリシー評価を遅らせることに注意してください。\nBanditPolicyおよびその他のポリシーの詳細については、[ここ](https://docs.microsoft.com/azure/machine-learning/service/how-to-tune-hyperparameters#specify-an-early-termination-policy)を参照してください。" 251 | }, 252 | { 253 | "metadata": { 254 | "trusted": true 255 | }, 256 | "cell_type": "code", 257 | "source": "early_termination_policy = BanditPolicy(slack_factor=0.15, evaluation_interval=1, delay_evaluation=10)", 258 | "execution_count": null, 259 | "outputs": [] 260 | }, 261 | { 262 | "metadata": {}, 263 | "cell_type": "markdown", 264 | "source": "### 設定の定義\n\n設定には`HyperDriveRunConfig()`を使用します。 \n詳細は[こちらの公式ドキュメント](https://docs.microsoft.com/en-us/python/api/azureml-train-core/azureml.train.hyperdrive.hyperdriverunconfig?view=azure-ml-py)を確認してください。 \n\n`primary_metric_name='best_val_acc'`で検証データへの精度を評価指標として使用する事を決定し、`primary_metric_goal=PrimaryMetricGoal.MAXIMIZE`でその値が最大となる事を目指すと設定しています。 \n`MINIMIZE`と指定することによって、最小にする事を目指すことも可能です。 \n\nまた`max_total_runs=4`で学習実行数を指定、`max_concurrent_runs=8`で同時に学習を行う数を指定しています。" 265 | }, 266 | { 267 | "metadata": { 268 | "trusted": true 269 | }, 270 | "cell_type": "code", 271 | "source": "hyperdrive_run_config = HyperDriveRunConfig(estimator=estimator,\n hyperparameter_sampling=param_sampling, \n policy=early_termination_policy,\n primary_metric_name='best_val_acc',\n primary_metric_goal=PrimaryMetricGoal.MAXIMIZE,\n max_total_runs=8,\n max_concurrent_runs=4)", 272 | "execution_count": null, 273 | "outputs": [] 274 | }, 275 | { 276 | "metadata": {}, 277 | "cell_type": "markdown", 278 | "source": "これで設定が完了したので、早速学習を行ってみましょう。\n\n学習時の環境にもよりますが、並列度 4で、**10分程度**かかります。\n\n初期設定の通り、並列度 4、最大8、AmlCompute 4の場合、20-25分程度かかります。" 279 | }, 280 | { 281 | "metadata": { 282 | "trusted": true 283 | }, 284 | "cell_type": "code", 285 | "source": "# HyperDrive runの開始\nhyperdrive_run = experiment.submit(hyperdrive_run_config)", 286 | "execution_count": null, 287 | "outputs": [] 288 | }, 289 | { 290 | "metadata": { 291 | "scrolled": false, 292 | "trusted": true 293 | }, 294 | "cell_type": "code", 295 | "source": "from azureml.widgets import RunDetails\n\nRunDetails(hyperdrive_run).show()", 296 | "execution_count": null, 297 | "outputs": [] 298 | }, 299 | { 300 | "metadata": { 301 | "trusted": true 302 | }, 303 | "cell_type": "code", 304 | "source": "hyperdrive_run.wait_for_completion(show_output=True)", 305 | "execution_count": null, 306 | "outputs": [] 307 | }, 308 | { 309 | "metadata": {}, 310 | "cell_type": "markdown", 311 | "source": "### 最適なモデルの取得\n\n\n\nすべての実行が完了すると、モデルを最も正確に生成した実行を見つけることができます。" 312 | }, 313 | { 314 | "metadata": { 315 | "trusted": true 316 | }, 317 | "cell_type": "code", 318 | "source": "best_run = hyperdrive_run.get_best_run_by_primary_metric()\nbest_run_metrics = best_run.get_metribcs()\nprint(best_run)", 319 | "execution_count": null, 320 | "outputs": [] 321 | }, 322 | { 323 | "metadata": {}, 324 | "cell_type": "markdown", 325 | "source": "最後に、最も優れた実行結果からモデルをワークスペースに登録します。 \n`model_path`パラメータはあなたの` output`ディレクトリのモデルファイルへのリモートVM上の相対パスを取ります。次のセクションでは、この登録モデルをWebサービスとしてデプロイします。" 326 | }, 327 | { 328 | "metadata": {}, 329 | "cell_type": "markdown", 330 | "source": "## 最適なモデルのデプロイ" 331 | }, 332 | { 333 | "metadata": { 334 | "trusted": true 335 | }, 336 | "cell_type": "code", 337 | "source": "model = best_run.register_model(model_name = 'Chainer-dogcat', model_path = 'outputs/model.pt')\nprint(model.name, model.id, model.version, sep = '\\t')", 338 | "execution_count": null, 339 | "outputs": [] 340 | }, 341 | { 342 | "metadata": {}, 343 | "cell_type": "markdown", 344 | "source": "# 以降、開発中!!!\n\nここ以降まだ確認できていません。" 345 | }, 346 | { 347 | "metadata": {}, 348 | "cell_type": "markdown", 349 | "source": "### スコアリングスクリプトの作成\n\n- `init()`:この関数では、通常モデルを `global`オブジェクトにロードします。この関数はDockerコンテナが起動されたときに一度だけ実行されます。\n- `run(input_data)`:この関数では、新たな入力データ対して学習済みモデルを使用して推論を実行します。通常は入力と出力は通常シリアライゼーションとデシリアライゼーションのフォーマットとしてJSONを使用しますが、他のフォーマットも使用することが可能です。" 350 | }, 351 | { 352 | "metadata": { 353 | "trusted": true 354 | }, 355 | "cell_type": "code", 356 | "source": "%%writefile chainer-doc_cat/score.py\n\nimport torch\nimport torch.nn as nn\nfrom torchvision import transforms\nimport json\n\nfrom azureml.core.model import Model\n\n\ndef init():\n global model\n model_path = Model.get_model_path('pytorch-dogcat')\n model = torch.load(model_path, map_location=lambda storage, loc: storage)\n model.eval()\n\n\ndef run(input_data):\n input_data = torch.tensor(json.loads(input_data)['data'])\n\n # get prediction\n with torch.no_grad():\n output = model(input_data)\n classes = ['cat', 'dog']\n softmax = nn.Softmax(dim=1)\n pred_probs = softmax(output).numpy()[0]\n index = torch.argmax(output, 1)\n\n result = {\"label\": classes[index], \"probability\": str(pred_probs[index])}\n return result", 357 | "execution_count": null, 358 | "outputs": [] 359 | }, 360 | { 361 | "metadata": {}, 362 | "cell_type": "markdown", 363 | "source": "### 環境ファイルを作成する\n\nスコアリングスクリプトのすべてのパッケージ依存関係を指定する環境ファイル( `myenv.yml`)を作成する必要があります。このファイルは、Azure MLによってこれらのすべての依存関係がDockerイメージにインストールされるようにするために使用されます。この場合、 `azureml-core`、` torch`、そして `torchvision`が必要になります。" 364 | }, 365 | { 366 | "metadata": { 367 | "trusted": true 368 | }, 369 | "cell_type": "code", 370 | "source": "from azureml.core.conda_dependencies import CondaDependencies \n\nmyenv = CondaDependencies.create(pip_packages=['azureml-defaults', 'torch', 'torchvision'])\n\nwith open(\"myenv.yml\",\"w\") as f:\n f.write(myenv.serialize_to_string())\n \nprint(myenv.serialize_to_string())", 371 | "execution_count": null, 372 | "outputs": [] 373 | }, 374 | { 375 | "metadata": {}, 376 | "cell_type": "markdown", 377 | "source": "### Dockerイメージの設定\n\nACIコンテナーを構築するために使用するDockerイメージを構成します。 \n詳細については[こちらの公式ドキュメント](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.image.containerimage?view=azure-ml-py)を確認してください。 " 378 | }, 379 | { 380 | "metadata": { 381 | "trusted": true 382 | }, 383 | "cell_type": "code", 384 | "source": "from azureml.core.image import ContainerImage\n\nimage_config = ContainerImage.image_configuration(execution_script='pytorch_score.py', \n runtime='python', \n conda_file='myenv.yml',\n description='Image with hymenoptera model')", 385 | "execution_count": null, 386 | "outputs": [] 387 | }, 388 | { 389 | "metadata": {}, 390 | "cell_type": "markdown", 391 | "source": "### ACIコンテナの設定\n\nデプロイのための準備がほぼ整いました。 \nACIコンテナに必要なCPUの数とギガバイトのRAMを指定するためのデプロイメント構成ファイルを作成します。 \nそれは作成したモデルに依存しますが、一般的なモデルではデフォルトの `1`コアと` 1`ギガバイトのRAMで十分なケースが多いです。 " 392 | }, 393 | { 394 | "metadata": { 395 | "trusted": true 396 | }, 397 | "cell_type": "code", 398 | "source": "from azureml.core.webservice import AciWebservice\n\naciconfig = AciWebservice.deploy_configuration(cpu_cores=1, \n memory_gb=1, \n tags={'data': 'dog_cat', 'method':'transfer learning', 'framework':'chainer'},\n description='Classify dogs/cats using transfer learning with Chainer')", 399 | "execution_count": null, 400 | "outputs": [] 401 | }, 402 | { 403 | "metadata": { 404 | "trusted": true 405 | }, 406 | "cell_type": "code", 407 | "source": "from azureml.core.webservice import AciWebservice\n\naciconfig = AciWebservice.deploy_configuration(cpu_cores=1, \n memory_gb=1, \n tags={'data': 'dogcat', 'method':'transfer learning', 'framework':'pytorch'},\n description='Classify ants/bees using transfer learning with PyTorch')", 408 | "execution_count": null, 409 | "outputs": [] 410 | }, 411 | { 412 | "metadata": {}, 413 | "cell_type": "markdown", 414 | "source": "### Container Instances にデプロイする\n\n最後に、登録したモデルからWebサービスをデプロイしましょう。 \n前の手順で作成したACI設定ファイルとイメージ設定ファイルを使用してWebサービスをデプロイします。 \n\nリストの中の `model`オブジェクトを` models`パラメータに渡します。 \n複数の登録済みモデルをデプロイする場合は、このリストに他のモデルを追加してください。  " 415 | }, 416 | { 417 | "metadata": { 418 | "trusted": true 419 | }, 420 | "cell_type": "code", 421 | "source": "%%time\nfrom azureml.core.webservice import Webservice\n\nservice_name = 'classify-dog-cat'\nservice = Webservice.deploy_from_model(workspace=ws,\n name=service_name,\n models=[model],\n image_config=image_config,\n deployment_config=aciconfig,)\n\nservice.wait_for_deployment(show_output=True)\nprint(service.state)", 422 | "execution_count": null, 423 | "outputs": [] 424 | }, 425 | { 426 | "metadata": {}, 427 | "cell_type": "markdown", 428 | "source": "通常デプロイには7~8分かかります。 \n下記のように表示されればデプロイが成功しています。 \n\n```\nSucceededACI service creation operation finished, operation \"Succeeded\"\n\n```\n\n#### デプロイがうまくいかない場合\n\nもし、何らかの理由でデプロイが失敗して再デプロイする必要がある場合は、必ずサービスを`service.delete()`で削除してください。 \n\n**また、デプロイに問題が発生した場合、まず下記のコマンドを実行して、サービスからログを取得しましょう。** \n\n`service.get_logs()`" 429 | }, 430 | { 431 | "metadata": {}, 432 | "cell_type": "markdown", 433 | "source": "## デプロイされたサービスをテストする\n\n最後に、デプロイしたWebサービスをテストしましょう。 \nデータをJSON文字列としてACIでホストされているWebサービスに送信し、SDKの `run` APIを使用してサービスを呼び出します。 \nここで、検証データからイメージを取得して推論を実行します。" 434 | }, 435 | { 436 | "metadata": { 437 | "trusted": true 438 | }, 439 | "cell_type": "code", 440 | "source": "import os, json\nfrom PIL import Image\nimport matplotlib.pyplot as plt\n\nplt.imshow(Image.open('test_img2.jpeg'))", 441 | "execution_count": null, 442 | "outputs": [] 443 | }, 444 | { 445 | "metadata": {}, 446 | "cell_type": "markdown", 447 | "source": "画像データに対して学習時と同じ前処理を適応し、推論が実行できる状態に変更します。 " 448 | }, 449 | { 450 | "metadata": { 451 | "trusted": true 452 | }, 453 | "cell_type": "code", 454 | "source": "import torch\nfrom torchvision import transforms\n \ndef preprocess(image_file):\n \"\"\"Preprocess the input image.\"\"\"\n data_transforms = transforms.Compose([\n transforms.Resize(256),\n transforms.CenterCrop(224),\n transforms.ToTensor(),\n transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n ])\n\n image = Image.open(image_file)\n image = data_transforms(image).float()\n image = torch.tensor(image)\n image = image.unsqueeze(0)\n return image.numpy()", 455 | "execution_count": null, 456 | "outputs": [] 457 | }, 458 | { 459 | "metadata": { 460 | "trusted": true 461 | }, 462 | "cell_type": "code", 463 | "source": "input_data = preprocess('test_img2.jpeg')\nresult = service.run(input_data=json.dumps({'data': input_data.tolist()}))\nprint(result)", 464 | "execution_count": null, 465 | "outputs": [] 466 | }, 467 | { 468 | "metadata": {}, 469 | "cell_type": "markdown", 470 | "source": "うまく推論できていることが確認できました。 \nこれで自身のデータに対してもAzure MLを用いて、GPUクラスタを用いてのハイパーパラメータの調整、そしてデプロイまでを行うことのできる力がつきました。\n\n## 後片付け\n\nWebサービスが不要になったら、API呼び出しで簡単に削除しておきましょう。" 471 | }, 472 | { 473 | "metadata": { 474 | "trusted": true 475 | }, 476 | "cell_type": "code", 477 | "source": "service.delete()", 478 | "execution_count": null, 479 | "outputs": [] 480 | }, 481 | { 482 | "metadata": {}, 483 | "cell_type": "markdown", 484 | "source": "これでハンズオンは終了です。 \n皆さんお疲れ様でした。" 485 | } 486 | ], 487 | "metadata": { 488 | "kernelspec": { 489 | "name": "python36", 490 | "display_name": "Python 3.6", 491 | "language": "python" 492 | }, 493 | "language_info": { 494 | "mimetype": "text/x-python", 495 | "nbconvert_exporter": "python", 496 | "name": "python", 497 | "pygments_lexer": "ipython3", 498 | "version": "3.6.6", 499 | "file_extension": ".py", 500 | "codemirror_mode": { 501 | "version": 3, 502 | "name": "ipython" 503 | } 504 | } 505 | }, 506 | "nbformat": 4, 507 | "nbformat_minor": 2 508 | } -------------------------------------------------------------------------------- /11.automated-machine-learning_classification_auto-ml-classification.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Copyright (c) Microsoft Corporation. All rights reserved.\n", 8 | "\n", 9 | "Licensed under the MIT License." 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "# Automated Machine Learning\n", 17 | "_**Classification with Local Compute**_\n", 18 | "\n", 19 | "## Contents\n", 20 | "1. [Introduction](#Introduction)\n", 21 | "1. [Setup](#Setup)\n", 22 | "1. [Data](#Data)\n", 23 | "1. [Train](#Train)\n", 24 | "1. [Results](#Results)\n", 25 | "1. [Test](#Test)\n", 26 | "\n" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "## Introduction\n", 34 | "\n", 35 | "In this example we use the scikit-learn's [digit dataset](http://scikit-learn.org/stable/datasets/index.html#optical-recognition-of-handwritten-digits-dataset) to showcase how you can use AutoML for a simple classification problem.\n", 36 | "\n", 37 | "Make sure you have executed the [configuration](../../../configuration.ipynb) before running this notebook.\n", 38 | "\n", 39 | "In this notebook you will learn how to:\n", 40 | "1. Create an `Experiment` in an existing `Workspace`.\n", 41 | "2. Configure AutoML using `AutoMLConfig`.\n", 42 | "3. Train the model using local compute.\n", 43 | "4. Explore the results.\n", 44 | "5. Test the best fitted model." 45 | ] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "metadata": {}, 50 | "source": [ 51 | "## Setup\n", 52 | "\n", 53 | "As part of the setup you have already created an Azure ML `Workspace` object. For AutoML you will need to create an `Experiment` object, which is a named object in a `Workspace` used to run experiments." 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": null, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "import logging\n", 63 | "\n", 64 | "from matplotlib import pyplot as plt\n", 65 | "import numpy as np\n", 66 | "import pandas as pd\n", 67 | "from sklearn import datasets\n", 68 | "\n", 69 | "import azureml.core\n", 70 | "from azureml.core.experiment import Experiment\n", 71 | "from azureml.core.workspace import Workspace\n", 72 | "from azureml.train.automl import AutoMLConfig" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": null, 78 | "metadata": {}, 79 | "outputs": [], 80 | "source": [ 81 | "ws = Workspace.from_config()\n", 82 | "\n", 83 | "# Choose a name for the experiment and specify the project folder.\n", 84 | "experiment_name = 'automl-local-classification'\n", 85 | "project_folder = './sample_projects/automl-local-classification'\n", 86 | "\n", 87 | "experiment = Experiment(ws, experiment_name)\n", 88 | "\n", 89 | "output = {}\n", 90 | "output['SDK version'] = azureml.core.VERSION\n", 91 | "output['Subscription ID'] = ws.subscription_id\n", 92 | "output['Workspace Name'] = ws.name\n", 93 | "output['Resource Group'] = ws.resource_group\n", 94 | "output['Location'] = ws.location\n", 95 | "output['Project Directory'] = project_folder\n", 96 | "output['Experiment Name'] = experiment.name\n", 97 | "pd.set_option('display.max_colwidth', -1)\n", 98 | "outputDf = pd.DataFrame(data = output, index = [''])\n", 99 | "outputDf.T" 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "metadata": {}, 105 | "source": [ 106 | "Opt-in diagnostics for better experience, quality, and security of future releases." 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": null, 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [ 115 | "from azureml.telemetry import set_diagnostics_collection\n", 116 | "set_diagnostics_collection(send_diagnostics = True)" 117 | ] 118 | }, 119 | { 120 | "cell_type": "markdown", 121 | "metadata": {}, 122 | "source": [ 123 | "## Data\n", 124 | "\n", 125 | "This uses scikit-learn's [load_digits](http://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_digits.html) method." 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": null, 131 | "metadata": {}, 132 | "outputs": [], 133 | "source": [ 134 | "digits = datasets.load_digits()\n", 135 | "\n", 136 | "# Exclude the first 100 rows from training so that they can be used for test.\n", 137 | "X_train = digits.data[100:,:]\n", 138 | "y_train = digits.target[100:]" 139 | ] 140 | }, 141 | { 142 | "cell_type": "markdown", 143 | "metadata": {}, 144 | "source": [ 145 | "## Train\n", 146 | "\n", 147 | "Instantiate an `AutoMLConfig` object to specify the settings and data used to run the experiment.\n", 148 | "\n", 149 | "|Property|Description|\n", 150 | "|-|-|\n", 151 | "|**task**|classification or regression|\n", 152 | "|**primary_metric**|This is the metric that you want to optimize. Classification supports the following primary metrics:
accuracy
AUC_weighted
average_precision_score_weighted
norm_macro_recall
precision_score_weighted|\n", 153 | "|**iteration_timeout_minutes**|Time limit in minutes for each iteration.|\n", 154 | "|**iterations**|Number of iterations. In each iteration AutoML trains a specific pipeline with the data.|\n", 155 | "|**n_cross_validations**|Number of cross validation splits.|\n", 156 | "|**X**|(sparse) array-like, shape = [n_samples, n_features]|\n", 157 | "|**y**|(sparse) array-like, shape = [n_samples, ], [n_samples, n_classes]
Multi-class targets. An indicator matrix turns on multilabel classification. This should be an array of integers.|\n", 158 | "|**path**|Relative path to the project folder. AutoML stores configuration files for the experiment under this folder. You can specify a new empty folder.|" 159 | ] 160 | }, 161 | { 162 | "cell_type": "code", 163 | "execution_count": null, 164 | "metadata": {}, 165 | "outputs": [], 166 | "source": [ 167 | "automl_config = AutoMLConfig(task = 'classification',\n", 168 | " debug_log = 'automl_errors.log',\n", 169 | " primary_metric = 'AUC_weighted',\n", 170 | " iteration_timeout_minutes = 60,\n", 171 | " iterations = 25,\n", 172 | " n_cross_validations = 3,\n", 173 | " verbosity = logging.INFO,\n", 174 | " X = X_train, \n", 175 | " y = y_train,\n", 176 | " path = project_folder)" 177 | ] 178 | }, 179 | { 180 | "cell_type": "markdown", 181 | "metadata": {}, 182 | "source": [ 183 | "Call the `submit` method on the experiment object and pass the run configuration. Execution of local runs is synchronous. Depending on the data and the number of iterations this can run for a while.\n", 184 | "In this example, we specify `show_output = True` to print currently running iterations to the console." 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "execution_count": null, 190 | "metadata": {}, 191 | "outputs": [], 192 | "source": [ 193 | "local_run = experiment.submit(automl_config, show_output = True)" 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": null, 199 | "metadata": {}, 200 | "outputs": [], 201 | "source": [ 202 | "local_run" 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": {}, 208 | "source": [ 209 | "Optionally, you can continue an interrupted local run by calling `continue_experiment` without the `iterations` parameter, or run more iterations for a completed run by specifying the `iterations` parameter:" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": null, 215 | "metadata": {}, 216 | "outputs": [], 217 | "source": [ 218 | "local_run = local_run.continue_experiment(X = X_train, \n", 219 | " y = y_train, \n", 220 | " show_output = True,\n", 221 | " iterations = 5)" 222 | ] 223 | }, 224 | { 225 | "cell_type": "markdown", 226 | "metadata": {}, 227 | "source": [ 228 | "## Results" 229 | ] 230 | }, 231 | { 232 | "cell_type": "markdown", 233 | "metadata": {}, 234 | "source": [ 235 | "#### Widget for Monitoring Runs\n", 236 | "\n", 237 | "The widget will first report a \"loading\" status while running the first iteration. After completing the first iteration, an auto-updating graph and table will be shown. The widget will refresh once per minute, so you should see the graph update as child runs complete.\n", 238 | "\n", 239 | "**Note:** The widget displays a link at the bottom. Use this link to open a web interface to explore the individual run details." 240 | ] 241 | }, 242 | { 243 | "cell_type": "code", 244 | "execution_count": null, 245 | "metadata": {}, 246 | "outputs": [], 247 | "source": [ 248 | "from azureml.widgets import RunDetails\n", 249 | "RunDetails(local_run).show() " 250 | ] 251 | }, 252 | { 253 | "cell_type": "markdown", 254 | "metadata": {}, 255 | "source": [ 256 | "\n", 257 | "#### Retrieve All Child Runs\n", 258 | "You can also use SDK methods to fetch all the child runs and see individual metrics that we log." 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": null, 264 | "metadata": {}, 265 | "outputs": [], 266 | "source": [ 267 | "children = list(local_run.get_children())\n", 268 | "metricslist = {}\n", 269 | "for run in children:\n", 270 | " properties = run.get_properties()\n", 271 | " metrics = {k: v for k, v in run.get_metrics().items() if isinstance(v, float)}\n", 272 | " metricslist[int(properties['iteration'])] = metrics\n", 273 | "\n", 274 | "rundata = pd.DataFrame(metricslist).sort_index(1)\n", 275 | "rundata" 276 | ] 277 | }, 278 | { 279 | "cell_type": "markdown", 280 | "metadata": {}, 281 | "source": [ 282 | "### Retrieve the Best Model\n", 283 | "\n", 284 | "Below we select the best pipeline from our iterations. The `get_output` method returns the best run and the fitted model. The Model includes the pipeline and any pre-processing. Overloads on `get_output` allow you to retrieve the best run and fitted model for *any* logged metric or for a particular *iteration*." 285 | ] 286 | }, 287 | { 288 | "cell_type": "code", 289 | "execution_count": null, 290 | "metadata": {}, 291 | "outputs": [], 292 | "source": [ 293 | "best_run, fitted_model = local_run.get_output()\n", 294 | "print(best_run)\n", 295 | "print(fitted_model)" 296 | ] 297 | }, 298 | { 299 | "cell_type": "markdown", 300 | "metadata": {}, 301 | "source": [ 302 | "#### Best Model Based on Any Other Metric\n", 303 | "Show the run and the model that has the smallest `log_loss` value:" 304 | ] 305 | }, 306 | { 307 | "cell_type": "code", 308 | "execution_count": null, 309 | "metadata": {}, 310 | "outputs": [], 311 | "source": [ 312 | "lookup_metric = \"log_loss\"\n", 313 | "best_run, fitted_model = local_run.get_output(metric = lookup_metric)\n", 314 | "print(best_run)\n", 315 | "print(fitted_model)" 316 | ] 317 | }, 318 | { 319 | "cell_type": "markdown", 320 | "metadata": {}, 321 | "source": [ 322 | "#### Model from a Specific Iteration\n", 323 | "Show the run and the model from the third iteration:" 324 | ] 325 | }, 326 | { 327 | "cell_type": "code", 328 | "execution_count": null, 329 | "metadata": {}, 330 | "outputs": [], 331 | "source": [ 332 | "iteration = 3\n", 333 | "third_run, third_model = local_run.get_output(iteration = iteration)\n", 334 | "print(third_run)\n", 335 | "print(third_model)" 336 | ] 337 | }, 338 | { 339 | "cell_type": "markdown", 340 | "metadata": {}, 341 | "source": [ 342 | "## Test \n", 343 | "\n", 344 | "#### Load Test Data" 345 | ] 346 | }, 347 | { 348 | "cell_type": "code", 349 | "execution_count": null, 350 | "metadata": {}, 351 | "outputs": [], 352 | "source": [ 353 | "digits = datasets.load_digits()\n", 354 | "X_test = digits.data[:10, :]\n", 355 | "y_test = digits.target[:10]\n", 356 | "images = digits.images[:10]" 357 | ] 358 | }, 359 | { 360 | "cell_type": "markdown", 361 | "metadata": {}, 362 | "source": [ 363 | "#### Testing Our Best Fitted Model\n", 364 | "We will try to predict 2 digits and see how our model works." 365 | ] 366 | }, 367 | { 368 | "cell_type": "code", 369 | "execution_count": null, 370 | "metadata": {}, 371 | "outputs": [], 372 | "source": [ 373 | "# Randomly select digits and test.\n", 374 | "for index in np.random.choice(len(y_test), 2, replace = False):\n", 375 | " print(index)\n", 376 | " predicted = fitted_model.predict(X_test[index:index + 1])[0]\n", 377 | " label = y_test[index]\n", 378 | " title = \"Label value = %d Predicted value = %d \" % (label, predicted)\n", 379 | " fig = plt.figure(1, figsize = (3,3))\n", 380 | " ax1 = fig.add_axes((0,0,.8,.8))\n", 381 | " ax1.set_title(title)\n", 382 | " plt.imshow(images[index], cmap = plt.cm.gray_r, interpolation = 'nearest')\n", 383 | " plt.show()" 384 | ] 385 | } 386 | ], 387 | "metadata": { 388 | "authors": [ 389 | { 390 | "name": "savitam" 391 | } 392 | ], 393 | "kernelspec": { 394 | "display_name": "Python 3.6", 395 | "language": "python", 396 | "name": "python36" 397 | }, 398 | "language_info": { 399 | "codemirror_mode": { 400 | "name": "ipython", 401 | "version": 3 402 | }, 403 | "file_extension": ".py", 404 | "mimetype": "text/x-python", 405 | "name": "python", 406 | "nbconvert_exporter": "python", 407 | "pygments_lexer": "ipython3", 408 | "version": "3.6.6" 409 | } 410 | }, 411 | "nbformat": 4, 412 | "nbformat_minor": 2 413 | } -------------------------------------------------------------------------------- /12.automated-machine-learning_classification-with-deployment_auto-ml-classification-with-deployment.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Copyright (c) Microsoft Corporation. All rights reserved.\n", 8 | "\n", 9 | "Licensed under the MIT License." 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "# Automated Machine Learning\n", 17 | "_**Classification with Deployment**_\n", 18 | "\n", 19 | "## Contents\n", 20 | "1. [Introduction](#Introduction)\n", 21 | "1. [Setup](#Setup)\n", 22 | "1. [Train](#Train)\n", 23 | "1. [Deploy](#Deploy)\n", 24 | "1. [Test](#Test)" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "## Introduction\n", 32 | "\n", 33 | "In this example we use the scikit learn's [digit dataset](http://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_digits.html) to showcase how you can use AutoML for a simple classification problem and deploy it to an Azure Container Instance (ACI).\n", 34 | "\n", 35 | "Make sure you have executed the [configuration](../../../configuration.ipynb) before running this notebook.\n", 36 | "\n", 37 | "In this notebook you will learn how to:\n", 38 | "1. Create an experiment using an existing workspace.\n", 39 | "2. Configure AutoML using `AutoMLConfig`.\n", 40 | "3. Train the model using local compute.\n", 41 | "4. Explore the results.\n", 42 | "5. Register the model.\n", 43 | "6. Create a container image.\n", 44 | "7. Create an Azure Container Instance (ACI) service.\n", 45 | "8. Test the ACI service." 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "## Setup\n", 53 | "\n", 54 | "As part of the setup you have already created an Azure ML `Workspace` object. For AutoML you will need to create an `Experiment` object, which is a named object in a `Workspace` used to run experiments." 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "import json\n", 64 | "import logging\n", 65 | "\n", 66 | "from matplotlib import pyplot as plt\n", 67 | "import numpy as np\n", 68 | "import pandas as pd\n", 69 | "from sklearn import datasets\n", 70 | "\n", 71 | "import azureml.core\n", 72 | "from azureml.core.experiment import Experiment\n", 73 | "from azureml.core.workspace import Workspace\n", 74 | "from azureml.train.automl import AutoMLConfig\n", 75 | "from azureml.train.automl.run import AutoMLRun" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": null, 81 | "metadata": {}, 82 | "outputs": [], 83 | "source": [ 84 | "ws = Workspace.from_config()\n", 85 | "\n", 86 | "# choose a name for experiment\n", 87 | "experiment_name = 'automl-local-classification'\n", 88 | "# project folder\n", 89 | "project_folder = './sample_projects/automl-local-classification'\n", 90 | "\n", 91 | "experiment=Experiment(ws, experiment_name)\n", 92 | "\n", 93 | "output = {}\n", 94 | "output['SDK version'] = azureml.core.VERSION\n", 95 | "output['Subscription ID'] = ws.subscription_id\n", 96 | "output['Workspace'] = ws.name\n", 97 | "output['Resource Group'] = ws.resource_group\n", 98 | "output['Location'] = ws.location\n", 99 | "output['Project Directory'] = project_folder\n", 100 | "output['Experiment Name'] = experiment.name\n", 101 | "pd.set_option('display.max_colwidth', -1)\n", 102 | "outputDf = pd.DataFrame(data = output, index = [''])\n", 103 | "outputDf.T" 104 | ] 105 | }, 106 | { 107 | "cell_type": "markdown", 108 | "metadata": {}, 109 | "source": [ 110 | "Opt-in diagnostics for better experience, quality, and security of future releases." 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": null, 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [ 119 | "from azureml.telemetry import set_diagnostics_collection\n", 120 | "set_diagnostics_collection(send_diagnostics = True)" 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "metadata": {}, 126 | "source": [ 127 | "## Train\n", 128 | "\n", 129 | "Instantiate a AutoMLConfig object. This defines the settings and data used to run the experiment.\n", 130 | "\n", 131 | "|Property|Description|\n", 132 | "|-|-|\n", 133 | "|**task**|classification or regression|\n", 134 | "|**primary_metric**|This is the metric that you want to optimize. Classification supports the following primary metrics:
accuracy
AUC_weighted
average_precision_score_weighted
norm_macro_recall
precision_score_weighted|\n", 135 | "|**iteration_timeout_minutes**|Time limit in minutes for each iteration.|\n", 136 | "|**iterations**|Number of iterations. In each iteration AutoML trains a specific pipeline with the data.|\n", 137 | "|**n_cross_validations**|Number of cross validation splits.|\n", 138 | "|**X**|(sparse) array-like, shape = [n_samples, n_features]|\n", 139 | "|**y**|(sparse) array-like, shape = [n_samples, ], [n_samples, n_classes]
Multi-class targets. An indicator matrix turns on multilabel classification. This should be an array of integers.|\n", 140 | "|**path**|Relative path to the project folder. AutoML stores configuration files for the experiment under this folder. You can specify a new empty folder.|" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": null, 146 | "metadata": {}, 147 | "outputs": [], 148 | "source": [ 149 | "digits = datasets.load_digits()\n", 150 | "X_train = digits.data[10:,:]\n", 151 | "y_train = digits.target[10:]\n", 152 | "\n", 153 | "automl_config = AutoMLConfig(task = 'classification',\n", 154 | " name = experiment_name,\n", 155 | " debug_log = 'automl_errors.log',\n", 156 | " primary_metric = 'AUC_weighted',\n", 157 | " iteration_timeout_minutes = 20,\n", 158 | " iterations = 10,\n", 159 | " n_cross_validations = 2,\n", 160 | " verbosity = logging.INFO,\n", 161 | " X = X_train, \n", 162 | " y = y_train,\n", 163 | " path = project_folder)" 164 | ] 165 | }, 166 | { 167 | "cell_type": "markdown", 168 | "metadata": {}, 169 | "source": [ 170 | "Call the `submit` method on the experiment object and pass the run configuration. Execution of local runs is synchronous. Depending on the data and the number of iterations this can run for a while.\n", 171 | "In this example, we specify `show_output = True` to print currently running iterations to the console." 172 | ] 173 | }, 174 | { 175 | "cell_type": "code", 176 | "execution_count": null, 177 | "metadata": {}, 178 | "outputs": [], 179 | "source": [ 180 | "local_run = experiment.submit(automl_config, show_output = True)" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": null, 186 | "metadata": {}, 187 | "outputs": [], 188 | "source": [ 189 | "local_run" 190 | ] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "metadata": {}, 195 | "source": [ 196 | "## Deploy\n", 197 | "\n", 198 | "### Retrieve the Best Model\n", 199 | "\n", 200 | "Below we select the best pipeline from our iterations. The `get_output` method on `automl_classifier` returns the best run and the fitted model for the last invocation. Overloads on `get_output` allow you to retrieve the best run and fitted model for *any* logged metric or for a particular *iteration*." 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": null, 206 | "metadata": {}, 207 | "outputs": [], 208 | "source": [ 209 | "best_run, fitted_model = local_run.get_output()" 210 | ] 211 | }, 212 | { 213 | "cell_type": "markdown", 214 | "metadata": {}, 215 | "source": [ 216 | "### Register the Fitted Model for Deployment\n", 217 | "If neither `metric` nor `iteration` are specified in the `register_model` call, the iteration with the best primary metric is registered." 218 | ] 219 | }, 220 | { 221 | "cell_type": "code", 222 | "execution_count": null, 223 | "metadata": {}, 224 | "outputs": [], 225 | "source": [ 226 | "description = 'AutoML Model'\n", 227 | "tags = None\n", 228 | "model = local_run.register_model(description = description, tags = tags)\n", 229 | "\n", 230 | "print(local_run.model_id) # This will be written to the script file later in the notebook." 231 | ] 232 | }, 233 | { 234 | "cell_type": "markdown", 235 | "metadata": {}, 236 | "source": [ 237 | "### Create Scoring Script" 238 | ] 239 | }, 240 | { 241 | "cell_type": "code", 242 | "execution_count": null, 243 | "metadata": {}, 244 | "outputs": [], 245 | "source": [ 246 | "%%writefile score.py\n", 247 | "import pickle\n", 248 | "import json\n", 249 | "import numpy\n", 250 | "import azureml.train.automl\n", 251 | "from sklearn.externals import joblib\n", 252 | "from azureml.core.model import Model\n", 253 | "\n", 254 | "\n", 255 | "def init():\n", 256 | " global model\n", 257 | " model_path = Model.get_model_path(model_name = '<>') # this name is model.id of model that we want to deploy\n", 258 | " # deserialize the model file back into a sklearn model\n", 259 | " model = joblib.load(model_path)\n", 260 | "\n", 261 | "def run(rawdata):\n", 262 | " try:\n", 263 | " data = json.loads(rawdata)['data']\n", 264 | " data = numpy.array(data)\n", 265 | " result = model.predict(data)\n", 266 | " except Exception as e:\n", 267 | " result = str(e)\n", 268 | " return json.dumps({\"error\": result})\n", 269 | " return json.dumps({\"result\":result.tolist()})" 270 | ] 271 | }, 272 | { 273 | "cell_type": "markdown", 274 | "metadata": {}, 275 | "source": [ 276 | "### Create a YAML File for the Environment" 277 | ] 278 | }, 279 | { 280 | "cell_type": "markdown", 281 | "metadata": {}, 282 | "source": [ 283 | "To ensure the fit results are consistent with the training results, the SDK dependency versions need to be the same as the environment that trains the model. Details about retrieving the versions can be found in notebook [12.auto-ml-retrieve-the-training-sdk-versions](12.auto-ml-retrieve-the-training-sdk-versions.ipynb)." 284 | ] 285 | }, 286 | { 287 | "cell_type": "code", 288 | "execution_count": null, 289 | "metadata": {}, 290 | "outputs": [], 291 | "source": [ 292 | "experiment_name = 'automl-local-classification'\n", 293 | "\n", 294 | "experiment = Experiment(ws, experiment_name)\n", 295 | "ml_run = AutoMLRun(experiment = experiment, run_id = local_run.id)" 296 | ] 297 | }, 298 | { 299 | "cell_type": "code", 300 | "execution_count": null, 301 | "metadata": {}, 302 | "outputs": [], 303 | "source": [ 304 | "dependencies = ml_run.get_run_sdk_dependencies(iteration = 7)" 305 | ] 306 | }, 307 | { 308 | "cell_type": "code", 309 | "execution_count": null, 310 | "metadata": {}, 311 | "outputs": [], 312 | "source": [ 313 | "for p in ['azureml-train-automl', 'azureml-sdk', 'azureml-core']:\n", 314 | " print('{}\\t{}'.format(p, dependencies[p]))" 315 | ] 316 | }, 317 | { 318 | "cell_type": "code", 319 | "execution_count": null, 320 | "metadata": {}, 321 | "outputs": [], 322 | "source": [ 323 | "from azureml.core.conda_dependencies import CondaDependencies\n", 324 | "\n", 325 | "myenv = CondaDependencies.create(conda_packages=['numpy','scikit-learn'], pip_packages=['azureml-sdk[automl]'])\n", 326 | "\n", 327 | "conda_env_file_name = 'myenv.yml'\n", 328 | "myenv.save_to_file('.', conda_env_file_name)" 329 | ] 330 | }, 331 | { 332 | "cell_type": "code", 333 | "execution_count": null, 334 | "metadata": {}, 335 | "outputs": [], 336 | "source": [ 337 | "# Substitute the actual version number in the environment file.\n", 338 | "# This is not strictly needed in this notebook because the model should have been generated using the current SDK version.\n", 339 | "# However, we include this in case this code is used on an experiment from a previous SDK version.\n", 340 | "\n", 341 | "with open(conda_env_file_name, 'r') as cefr:\n", 342 | " content = cefr.read()\n", 343 | "\n", 344 | "with open(conda_env_file_name, 'w') as cefw:\n", 345 | " cefw.write(content.replace(azureml.core.VERSION, dependencies['azureml-sdk']))\n", 346 | "\n", 347 | "# Substitute the actual model id in the script file.\n", 348 | "\n", 349 | "script_file_name = 'score.py'\n", 350 | "\n", 351 | "with open(script_file_name, 'r') as cefr:\n", 352 | " content = cefr.read()\n", 353 | "\n", 354 | "with open(script_file_name, 'w') as cefw:\n", 355 | " cefw.write(content.replace('<>', local_run.model_id))" 356 | ] 357 | }, 358 | { 359 | "cell_type": "markdown", 360 | "metadata": {}, 361 | "source": [ 362 | "### Create a Container Image" 363 | ] 364 | }, 365 | { 366 | "cell_type": "code", 367 | "execution_count": null, 368 | "metadata": {}, 369 | "outputs": [], 370 | "source": [ 371 | "from azureml.core.image import Image, ContainerImage\n", 372 | "\n", 373 | "image_config = ContainerImage.image_configuration(runtime= \"python\",\n", 374 | " execution_script = script_file_name,\n", 375 | " conda_file = conda_env_file_name,\n", 376 | " tags = {'area': \"digits\", 'type': \"automl_classification\"},\n", 377 | " description = \"Image for automl classification sample\")\n", 378 | "\n", 379 | "image = Image.create(name = \"automlsampleimage\",\n", 380 | " # this is the model object \n", 381 | " models = [model],\n", 382 | " image_config = image_config, \n", 383 | " workspace = ws)\n", 384 | "\n", 385 | "image.wait_for_creation(show_output = True)\n", 386 | "\n", 387 | "if image.creation_state == 'Failed':\n", 388 | " print(\"Image build log at: \" + image.image_build_log_uri)" 389 | ] 390 | }, 391 | { 392 | "cell_type": "markdown", 393 | "metadata": {}, 394 | "source": [ 395 | "### Deploy the Image as a Web Service on Azure Container Instance" 396 | ] 397 | }, 398 | { 399 | "cell_type": "code", 400 | "execution_count": null, 401 | "metadata": {}, 402 | "outputs": [], 403 | "source": [ 404 | "from azureml.core.webservice import AciWebservice\n", 405 | "\n", 406 | "aciconfig = AciWebservice.deploy_configuration(cpu_cores = 1, \n", 407 | " memory_gb = 1, \n", 408 | " tags = {'area': \"digits\", 'type': \"automl_classification\"}, \n", 409 | " description = 'sample service for Automl Classification')" 410 | ] 411 | }, 412 | { 413 | "cell_type": "code", 414 | "execution_count": null, 415 | "metadata": {}, 416 | "outputs": [], 417 | "source": [ 418 | "from azureml.core.webservice import Webservice\n", 419 | "\n", 420 | "aci_service_name = 'automl-sample-01'\n", 421 | "print(aci_service_name)\n", 422 | "aci_service = Webservice.deploy_from_image(deployment_config = aciconfig,\n", 423 | " image = image,\n", 424 | " name = aci_service_name,\n", 425 | " workspace = ws)\n", 426 | "aci_service.wait_for_deployment(True)\n", 427 | "print(aci_service.state)" 428 | ] 429 | }, 430 | { 431 | "cell_type": "markdown", 432 | "metadata": {}, 433 | "source": [ 434 | "### Delete a Web Service" 435 | ] 436 | }, 437 | { 438 | "cell_type": "code", 439 | "execution_count": null, 440 | "metadata": {}, 441 | "outputs": [], 442 | "source": [ 443 | "#aci_service.delete()" 444 | ] 445 | }, 446 | { 447 | "cell_type": "markdown", 448 | "metadata": {}, 449 | "source": [ 450 | "### Get Logs from a Deployed Web Service" 451 | ] 452 | }, 453 | { 454 | "cell_type": "code", 455 | "execution_count": null, 456 | "metadata": {}, 457 | "outputs": [], 458 | "source": [ 459 | "#aci_service.get_logs()" 460 | ] 461 | }, 462 | { 463 | "cell_type": "markdown", 464 | "metadata": {}, 465 | "source": [ 466 | "## Test" 467 | ] 468 | }, 469 | { 470 | "cell_type": "code", 471 | "execution_count": null, 472 | "metadata": {}, 473 | "outputs": [], 474 | "source": [ 475 | "#Randomly select digits and test\n", 476 | "digits = datasets.load_digits()\n", 477 | "X_test = digits.data[:10, :]\n", 478 | "y_test = digits.target[:10]\n", 479 | "images = digits.images[:10]\n", 480 | "\n", 481 | "for index in np.random.choice(len(y_test), 3, replace = False):\n", 482 | " print(index)\n", 483 | " test_sample = json.dumps({'data':X_test[index:index + 1].tolist()})\n", 484 | " predicted = aci_service.run(input_data = test_sample)\n", 485 | " label = y_test[index]\n", 486 | " predictedDict = json.loads(predicted)\n", 487 | " title = \"Label value = %d Predicted value = %s \" % ( label,predictedDict['result'][0])\n", 488 | " fig = plt.figure(1, figsize = (3,3))\n", 489 | " ax1 = fig.add_axes((0,0,.8,.8))\n", 490 | " ax1.set_title(title)\n", 491 | " plt.imshow(images[index], cmap = plt.cm.gray_r, interpolation = 'nearest')\n", 492 | " plt.show()" 493 | ] 494 | } 495 | ], 496 | "metadata": { 497 | "authors": [ 498 | { 499 | "name": "savitam" 500 | } 501 | ], 502 | "kernelspec": { 503 | "display_name": "Python 3.6", 504 | "language": "python", 505 | "name": "python36" 506 | }, 507 | "language_info": { 508 | "codemirror_mode": { 509 | "name": "ipython", 510 | "version": 3 511 | }, 512 | "file_extension": ".py", 513 | "mimetype": "text/x-python", 514 | "name": "python", 515 | "nbconvert_exporter": "python", 516 | "pygments_lexer": "ipython3", 517 | "version": "3.6.6" 518 | } 519 | }, 520 | "nbformat": 4, 521 | "nbformat_minor": 2 522 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Deep Learning Lab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AML-Handson 2 | Azure Machine Learning Hands-on 3 | 4 | # 必要なもの 5 | 6 | - Microsoft Account 7 | - Azure の Subscription 8 | 9 | お持ちない方は、Azure Free Trial へ。ただし、`GPU` インスタンスは *利用できません* ので、CPU のみでお願いします。 10 | 11 | https://azure.microsoft.com/ja-jp/free/ 12 | 13 | - Azure Notebook へのサインイン 14 | 15 | Azure Notebook の利用には Azureのアカウントがなくても行えます。Microsoft Account のみでOKです。 16 | 17 | ですが、このハンズオンでは *シングルサインオン* 出来るように、既存のAzure のアカウントで Azure Notebook にもログインできる、という前提で進めます。 18 | 19 | クイック スタート:サインインとユーザー ID の設定: 20 | 21 | https://docs.microsoft.com/ja-jp/azure/notebooks/quickstart-sign-in-azure-notebooks 22 | 23 | 24 | # Azure Machine Learning services の作成と構成 25 | 26 | ## 1. Azure Machine Learning ワークスペースの作成 27 | 28 | こちらのドキュメントを参考に、Azure Machine Learning ワークスペースを作成してください。 29 | 30 | スムーズにサンプルコードを動かすために、リージョン (データセンター) は、GPUインスタンスを使う関係で以下がおススメです。 31 | 32 | - 米国西部2 33 | - 米国東部 - こちらですと、FPGA での推論も使えます (Public Preview) 34 | 35 | - (**注**) 東南アジア - 一番近くにあるのですが、NCシリーズが **使えません**。AmlCompute を作成する際に、`NCv3` に変更してください。 36 | 37 | Azure どのリージョンで、どの製品が使えるのか: 38 | 39 | https://azure.microsoft.com/ja-jp/global-infrastructure/services/?products=virtual-machines 40 | 41 | Azure Machine Learning Services ワークスペースを作成し、管理する: 42 | 43 | https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-manage-workspace 44 | 45 | 46 | ## 2. Azure Notebook 上 へのハンズオンコンテンツのコピー (クローン) 47 | 48 | Github にあるコンテンツをクローンします。 49 | 50 | GitHub からプロジェクトをインポートする: 51 | 52 | https://docs.microsoft.com/ja-jp/azure/notebooks/create-clone-jupyter-notebooks#import-a-project-from-github 53 | 54 | 55 | インポート元 56 | 57 | ``` 58 | https://github.com/DeepLearningLab/AML-Handson 59 | ``` 60 | 61 | 62 | ノートブックで Azure Machine Learning service を使用する: 63 | 64 | https://docs.microsoft.com/ja-jp/azure/notebooks/use-machine-learning-services-jupyter-notebooks 65 | 66 | ## 3. Azure Notebook のプロジェクトから、Azure Machine Learning services のワークスペース への接続 67 | 68 | 接続文字列を作成します。 69 | 70 | 以下の Notebook を開いて、実行してください。 71 | 72 | ## [00.configuration.ipynb](./00.configuration.ipynb) 73 | 74 | Azure Machine Learning services の 利用確認 75 | 76 | - SDK の動作確認 77 | Azure Notebook には Azure Machine Learning services の Python SDK がインストール済みです 78 | - Workspace への接続情報ファイルの作成 (config.json) 79 | - (option) AmlCompute の作成 80 | 81 | Workspace のパラメーターは、Azure Portal にあります。 82 | 83 | https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-configure-environment#workspace 84 | 85 | 86 | # Azure Machine Learning services を使った深層学習の実行 87 | 88 | ## [01.train-deploy_pytorch.ipynb](./01.train-deploy_pytorch.ipynb) 89 | 90 | Azure Machine Learning の Python SDK を使った、学習部分について一通りの機能を試します。ここでは、PyTouch で学習を行います。 91 | 92 | - Workspace への接続 93 | - 学習用 VM の設定 94 | コード上は `GPU` クラスターを作っています。無料トライアルでは、即座に使えませんので、`vm_size` に `STANDARD_D2_V2` などを指定して、`CPU` クラスターへ変更ください。 95 | - DataStore の設定 96 | - 学習用のスクリプトの実行 (PyTorch) 97 | - 学習結果の可視化 98 | - Azure Container Instance へデプロイ 99 | - REST での推論実行 100 | 101 | 102 | ## [02.train-hyperparametertune-deploy_chainer.ipynb](./02.train-hyperparametertune-deploy_chainer.ipynb) 103 | 104 | Chainer を使っての、学習部分と、Hyperparamter Tuning について一通りの機能を試します。 105 | 106 | - Workspace への接続 107 | - 学習用 VM の設定 108 | - DataStore の設定 109 | - 学習用のスクリプトの実行 (Chainer) 110 | - 学習結果の可視化 111 | - Hyperparamter Turning の設定 112 | - 学習用のスクリプトの実行 (Chainer) 113 | - Azure Container Instance へデプロイ 114 | - REST での推論実行 115 | 116 | 117 | ## 他の Framework のサンプル 118 | 119 | TensorFlow などのサンプルコードはこちらになります。 120 | 121 | https://github.com/Azure/MachineLearningNotebooks/tree/master/how-to-use-azureml/training-with-deep-learning 122 | 123 | 124 | # GPU が使えない方のために 125 | 126 | CPU でも学習時間は比較的短い 有名なデータセットである MNIST を使ったものを試します。 127 | 128 | Source: 129 | 130 | https://github.com/Azure/MachineLearningNotebooks 131 | 132 | ## [11.automated-machine-learning_classification_auto-ml-classification.ipynb](11.automated-machine-learning_classification_auto-ml-classification.ipynb) 133 | 134 | Automated Machine Learning の機能を試します。MNISTがデータセットです。 135 | 136 | 137 | ## [12.automated-machine-learning_classification-with-deployment_auto-ml-classification-with-deployment.ipynb](12.automated-machine-learning_classification-with-deployment_auto-ml-classification-with-deployment.ipynb) 138 | 139 | Automated Machine Learning に加えて、Azure Container Instance へデプロイまで行います。 140 | 141 | 142 | # うまくいかなかったとき 143 | 144 | - Azure Notebook で Azure Machine Learning services の SDK が動作しない 145 | 146 | - 現在の Azure Machine Learning services の SDKは、 Python 3.6 で動作します。Azure NotebookのKernel で Pythonのバージョンを確認してください。 147 | 148 | - Azure Machine Learning services の Workspace 接続用のconfig.jsonファイル作成がうまくうごかない 149 | 150 | - config.json を手動で作成ください。 151 | 152 | 参照: ワークスペース構成ファイルを作成する 153 | 154 | https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-configure-environment#workspace 155 | 156 | - GPU クラスターの作成に失敗する 157 | 158 | 無料アカウントの場合、GPU インスタンスのクォータ (利用可能CPU数) が不足しています。0 になっています。もし GPU インスタンスを利用したいという場合は、従量課金のアカウントへ切り替えてください。 159 | 160 | 有償のアカウントの場合、GPUのコア数が不足している場合があります。サポートチケットを作成して、GPUコア数の引き上げのリクエストをしてください。即座に実施できるわけではなく、数営業日かかる場合もあります。 161 | 162 | Resource Manager の vCPU クォータを増やす要求 163 | 164 | https://docs.microsoft.com/ja-jp/azure/azure-supportability/resource-manager-core-quotas-request 165 | 166 | Azure リソースのクォータの管理と要求 167 | 168 | https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-manage-quotas 169 | 170 | 171 | - AmlCompute や、Data Science VM など、作成したはずなのに利用ができない 172 | 173 | `コンピューティング` として Azure Machine Learning Workspace内で設定がされているのに、CPUクォータ不足などがあって「失敗」という状況のまま、残っている場合があります。 174 | 175 | Azure Portal の、Azure Machine Learning services Workspace の `コンピューティング` から、削除ください。 176 | 177 | - AmlCompute -> 削除 178 | - Data Science VM -> でタッチ 179 | 180 | 181 | - Azure Machine Learning services 既知の問題 182 | 183 | https://docs.microsoft.com/ja-jp/azure/machine-learning/service/resource-known-issues 184 | 185 | # 参考ドキュメント 186 | 187 | - Azure Notebooks: 188 | 189 | https://docs.microsoft.com/ja-jp/azure/notebooks/ 190 | 191 | - Azure Machine Learning: 192 | 193 | https://docs.microsoft.com/ja-jp/azure/machine-learning/service/ 194 | 195 | - Visual Studio Code - Python Extention 196 | 197 | https://code.visualstudio.com/docs/python/python-tutorial 198 | -------------------------------------------------------------------------------- /data/dog-cat.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepLearningLab/AML-Handson/890ec2bc012a78299a74bf05c8bcc0d6d4bd9cf2/data/dog-cat.zip -------------------------------------------------------------------------------- /data/test_img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepLearningLab/AML-Handson/890ec2bc012a78299a74bf05c8bcc0d6d4bd9cf2/data/test_img.jpg -------------------------------------------------------------------------------- /data/test_img2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepLearningLab/AML-Handson/890ec2bc012a78299a74bf05c8bcc0d6d4bd9cf2/data/test_img2.jpeg -------------------------------------------------------------------------------- /docs/01_train-deploy.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Azure MLで学習済みモデルの作成からデプロイまで\n", 8 | "\n", 9 | "このチュートリアルでは、`Azure Machine Learning(Azure ML)Python SDK`を使用して、 \n", 10 | "モデルのトレーニング、ハイパーパラメーターの調整、およびデプロイを行います。 \n", 11 | "※ディープラーニングのフレームワークには`PyTorch`を使用します。 \n", 12 | "\n", 13 | "\n", 14 | "問題設定は[Transfer Learningチュートリアル](https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html)から、 Transfer Learning(転移学習)を使用してアリとハチの画像分類になります。 \n", 15 | "\n", 16 | "*転移学習とは?* \n", 17 | "転移学習とは学習済みモデルを使用して(ネットワークの構造と重みの再利用)、学習を行うことをさします。 \n", 18 | "類似のものとしてファインチューニングがありますが、学習済みモデルのネットワークの学習を行うのがファインチューニングになります。 \n", 19 | "転移学習では学習済みモデルのネットワーク自体の学習は行いません。(出力前の全結合層のみを学習させるのが一般的) " 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": {}, 25 | "source": [ 26 | "## 環境構築\n", 27 | "\n", 28 | "環境は「[Azure Machine Learning Services](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/) ワークスペース」にある`Azure Notebooks`を使用します。 \n", 29 | "Pythonの実行環境や、Azure ML Servicesを使用に必要な[Azure ML Python SDK](https://docs.microsoft.com/ja-jp/python/api/overview/azure/ml/intro?view=azure-ml-py)は既にインストールされています。  \n", 30 | "\n", 31 | "では、まずは[Azure Portal](https://azure.microsoft.com/ja-jp/features/azure-portal/)を開いて、`Azure Notebooks`の準備を行いましょう。 \n", 32 | "今回は解説しませんがローカル環境で行う際には[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/quickstart-create-workspace-with-python)を参照してください。 \n", 33 | "\n", 34 | "\n", 35 | "### リソースの作成\n", 36 | "\n", 37 | "まずは作業を行うためにAzure Machine Learning Services ワークスペースのリソースを作成します。 \n", 38 | "作成方法は[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/quickstart-get-started)を確認してください。 " 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "metadata": {}, 44 | "source": [ 45 | "### バージョンの確認" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": 2, 51 | "metadata": {}, 52 | "outputs": [ 53 | { 54 | "name": "stdout", 55 | "output_type": "stream", 56 | "text": [ 57 | "SDK version: 1.0.8\n" 58 | ] 59 | } 60 | ], 61 | "source": [ 62 | "# Check core SDK version number\n", 63 | "import azureml.core\n", 64 | "\n", 65 | "print(\"SDK version:\", azureml.core.VERSION)" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "AzrueML上では既にAzureML Python SDKが準備されているため、インストールする必要はありません。 " 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "metadata": {}, 78 | "source": [ 79 | "### ワークスペースの初期化\n", 80 | "\n", 81 | "[ワークスペース](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#workspace)の初期化を行います。 \n", 82 | "`Workspace.from_config()`は`config.json`ファイルを参照してワークスペースを初期化します。 \n", 83 | "\n", 84 | "#### configファイルの編集\n", 85 | "\n", 86 | "`config.json`ファイルは基本的に自動でこのように設定を反映されます。 \n", 87 | "自身で設定する際には下記のように編集します。 \n", 88 | "\n", 89 | "```json\n", 90 | "\n", 91 | "{\n", 92 | " \"subscription_id\": \"サブスクリプションID\",\n", 93 | " \"resource_group\": \"リソースグループ名\",\n", 94 | " \"workspace_name\": \"ワークスペース名\"\n", 95 | "}\n", 96 | "\n", 97 | "```\n", 98 | "\n", 99 | "上記の情報はAzure Portalの画面から確認することができます。 \n", 100 | "では、実行して、ワークスペースの初期化を行います。 \n", 101 | "\n", 102 | "初期化を行う時に、サインインを要求されるので、表示されるコードをコピーして、URLをクリックします。 \n", 103 | "遷移先の画面でコピーしたコードを入力することによって、サインインが完了します。 " 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": 4, 109 | "metadata": {}, 110 | "outputs": [ 111 | { 112 | "name": "stdout", 113 | "output_type": "stream", 114 | "text": [ 115 | "Found the config file in: /home/nbuser/library/config.json\n", 116 | "Performing interactive authentication. Please follow the instructions on the terminal.\n" 117 | ] 118 | }, 119 | { 120 | "name": "stderr", 121 | "output_type": "stream", 122 | "text": [ 123 | "To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code FK8RRVKBH to authenticate.\n" 124 | ] 125 | }, 126 | { 127 | "name": "stdout", 128 | "output_type": "stream", 129 | "text": [ 130 | "Interactive authentication successfully completed.\n", 131 | "Workspace name: dllab-azureml\n", 132 | "Azure region: eastus\n", 133 | "Resource group: dllab_azureml\n" 134 | ] 135 | } 136 | ], 137 | "source": [ 138 | "from azureml.core.workspace import Workspace\n", 139 | "\n", 140 | "ws = Workspace.from_config()\n", 141 | "print('Workspace name: ' + ws.name, \n", 142 | " 'Azure region: ' + ws.location, \n", 143 | " 'Resource group: ' + ws.resource_group, sep = '\\n')" 144 | ] 145 | }, 146 | { 147 | "cell_type": "markdown", 148 | "metadata": {}, 149 | "source": [ 150 | "## コンピューティング ターゲットの設定\n", 151 | "\n", 152 | "[コンピューティングターゲット](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#compute-target)を作成する必要があります。このチュートリアルではAzure ML managed compute ([AmlCompute](https://docs.microsoft.com/azure/machine-learning/service/how-to-set-up-training-targets#amlcompute))を使用します。 \n", 153 | "(コンピューティングターゲットは計算を実行する場所を決定するようなイメージです。)\n", 154 | "\n", 155 | "※AmlComputeの作成には約5分かかります。 \n", 156 | "その名前のAmlComputeが既にワークスペースにある場合、このコードは作成プロセスをスキップします。\n", 157 | "\n", 158 | "\n", 159 | "他のAzureサービスと同様に、Azure Machine Learningサービスに関連する特定のリソース(AmlComputeなど)には制限があります。 \n", 160 | "デフォルトの制限と、より多くのクォータを要求する方法についての[この記事](https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-manage-quotas)を読んでください。" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": 5, 166 | "metadata": {}, 167 | "outputs": [ 168 | { 169 | "name": "stdout", 170 | "output_type": "stream", 171 | "text": [ 172 | "Creating a new compute target...\n", 173 | "Creating\n", 174 | "Succeeded\n", 175 | "AmlCompute wait for completion finished\n", 176 | "Minimum number of nodes requested have been provisioned\n", 177 | "{'allocationState': 'Steady', 'allocationStateTransitionTime': '2019-01-28T10:06:04.204000+00:00', 'creationTime': '2019-01-28T10:04:39.638971+00:00', 'currentNodeCount': 0, 'errors': None, 'modifiedTime': '2019-01-28T10:06:08.656582+00:00', 'nodeStateCounts': {'idleNodeCount': 0, 'leavingNodeCount': 0, 'preemptedNodeCount': 0, 'preparingNodeCount': 0, 'runningNodeCount': 0, 'unusableNodeCount': 0}, 'provisioningState': 'Succeeded', 'provisioningStateTransitionTime': None, 'scaleSettings': {'minNodeCount': 0, 'maxNodeCount': 4, 'nodeIdleTimeBeforeScaleDown': 'PT120S'}, 'targetNodeCount': 0, 'vmPriority': 'Dedicated', 'vmSize': 'STANDARD_NC6'}\n" 178 | ] 179 | } 180 | ], 181 | "source": [ 182 | "from azureml.core.compute import ComputeTarget, AmlCompute\n", 183 | "from azureml.core.compute_target import ComputeTargetException\n", 184 | "\n", 185 | "# choose a name for your cluster\n", 186 | "cluster_name = \"gpucluster\"\n", 187 | "\n", 188 | "try:\n", 189 | " compute_target = ComputeTarget(workspace=ws, name=cluster_name)\n", 190 | " print('Found existing compute target.')\n", 191 | "except ComputeTargetException:\n", 192 | " print('Creating a new compute target...')\n", 193 | " compute_config = AmlCompute.provisioning_configuration(vm_size='STANDARD_NC6', \n", 194 | " max_nodes=4, vm_priority='dedicated')\n", 195 | "\n", 196 | " # create the cluster\n", 197 | " compute_target = ComputeTarget.create(ws, cluster_name, compute_config)\n", 198 | "\n", 199 | " compute_target.wait_for_completion(show_output=True)\n", 200 | "\n", 201 | "# Use the 'status' property to get a detailed status for the current cluster. \n", 202 | "print(compute_target.status.serialize())" 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": {}, 208 | "source": [ 209 | "上記のコードはGPUクラスターを作成します。 \n", 210 | "コードの中身を確認します。 \n", 211 | "`AmlCompute.provisioning_configuration()`でコンピューティング ターゲットの設定を行うことができます。 \n", 212 | "詳細は[こちらの公式ドキュメント](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.compute.amlcompute(class)?view=azure-ml-py)を確認してください。 \n", 213 | "\n", 214 | "\n", 215 | "### 仮想マシンのサイズの変更\n", 216 | "\n", 217 | "代わりにCPUクラスタを作成したい場合は、 `STANDARD_D2_V2`のように` vm_size`パラメータに異なるVMサイズを指定してください。 \n", 218 | "\n", 219 | "CPUのVMサイズは[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/virtual-machines/linux/sizes-general)を確認してください。 \n", 220 | "GPUのVMサイズは[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/virtual-machines/linux/sizes-gpu)を確認してください。 \n", 221 | "\n", 222 | "今回はNVIDIAのTesla K80が1枚の仮想マシン`STANDARD_NC6`を使用します。 \n", 223 | "計算リソースを増やすためにはNCの他のシリーズを使用するもしくはGPUの枚数を増やすことによって行うことが可能です。 \n", 224 | "\n", 225 | "\n", 226 | "### 仮想マシンの割り当ての設定\n", 227 | "\n", 228 | "Azureの仮想マシンのプライオリティ(優先度)を選択することができます。 \n", 229 | "選択肢は`dedicated`または`lowpriority`の2つから選択することができます。 \n", 230 | "(デフォルトでは`dedicated`が選択されています。) \n", 231 | "\n", 232 | "dedicatedは問題なく仮想マシンが割り当てられますが、lowpriorityは価格が安い代わりに割り込みが入る可能性などいくつかデメリットがあります。 \n", 233 | "しかし、価格が約8割ほど安くなるのは大きなメリットです。 \n", 234 | "\n", 235 | "\n", 236 | "### クラスターのノード数の設定\n", 237 | "\n", 238 | "`max_nodes`でコンピューティングでジョブを実行中に自動スケールアップする最大ノード数を指定することが可能です。 \n", 239 | "ノード数はVMの数を表すため最大数が増えると計算リソースが増えますが、同時に発生する料金も増えます。 " 240 | ] 241 | }, 242 | { 243 | "cell_type": "markdown", 244 | "metadata": {}, 245 | "source": [ 246 | "## GPUクラスタを使用しての学習の実行\n", 247 | "\n", 248 | "リモートコンピューティングクラスタを使用して学習する準備が整いました。 \n", 249 | "Pytorchでの学習のスクリプトと学習用のデータを準備します。 \n", 250 | "\n", 251 | "今回は事前に準備されたものを使用します。  " 252 | ] 253 | }, 254 | { 255 | "cell_type": "markdown", 256 | "metadata": {}, 257 | "source": [ 258 | "### プロジェクトディレクトリの作成\n", 259 | "\n", 260 | "学習実行に必要なコードを格納するディレクトリを作成します。 \n", 261 | "このディレクトリには学習を実行するコードと、それに依存関係のファイルなどを格納するする必要があります。 " 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": 6, 267 | "metadata": {}, 268 | "outputs": [], 269 | "source": [ 270 | "import os\n", 271 | "\n", 272 | "project_folder = './pytorch-hymenoptera'\n", 273 | "os.makedirs(project_folder, exist_ok=True)" 274 | ] 275 | }, 276 | { 277 | "cell_type": "markdown", 278 | "metadata": {}, 279 | "source": [ 280 | "今回は`pytorch-hymenoptera`という名前のプロジェクトフォルダを作成しました。 " 281 | ] 282 | }, 283 | { 284 | "cell_type": "markdown", 285 | "metadata": {}, 286 | "source": [ 287 | "### データセットの準備\n", 288 | "\n", 289 | "今回は[こちら](https://download.pytorch.org/tutorial/hymenoptera_data.zip)のデータセットを使用します。 \n", 290 | "(ダウンロードの必要はありません)\n", 291 | "\n", 292 | "\n", 293 | "こちらにはアリとミツバチの画像それぞれ約120個ずつの訓練データ、75個の検証データが含まれています。 \n", 294 | "学習用のスクリプトである`pytorch_train.py`内にデータセットをダウンロードして取得するコードがあるため、 \n", 295 | "こちらのデータは今回はダウンロードして準備する必要はありません。 " 296 | ] 297 | }, 298 | { 299 | "cell_type": "markdown", 300 | "metadata": {}, 301 | "source": [ 302 | "### 学習用スクリプトの準備\n", 303 | "\n", 304 | "学習用のスクリプトは用意されている`pytorch_train.py`を使用します。 \n", 305 | "\n", 306 | "\n", 307 | "### スクリプトの確認\n", 308 | "\n", 309 | "今回使用するスクリプトはこちらになります。 \n", 310 | "\n", 311 | "`pytorch_train.py` \n", 312 | "\n", 313 | "```python\n", 314 | "\n", 315 | "from __future__ import print_function, division\n", 316 | "import torch\n", 317 | "import torch.nn as nn\n", 318 | "import torch.optim as optim\n", 319 | "from torch.optim import lr_scheduler\n", 320 | "from torchvision import datasets, models, transforms\n", 321 | "import numpy as np\n", 322 | "import time\n", 323 | "import os\n", 324 | "import copy\n", 325 | "import argparse\n", 326 | "\n", 327 | "from azureml.core.run import Run\n", 328 | "# get the Azure ML run object\n", 329 | "run = Run.get_context()\n", 330 | "\n", 331 | "\n", 332 | "def load_data(data_dir):\n", 333 | " \"\"\"Load the train/val data.\"\"\"\n", 334 | "\n", 335 | " # Data augmentation and normalization for training\n", 336 | " # Just normalization for validation\n", 337 | " data_transforms = {\n", 338 | " 'train': transforms.Compose([\n", 339 | " transforms.RandomResizedCrop(224),\n", 340 | " transforms.RandomHorizontalFlip(),\n", 341 | " transforms.ToTensor(),\n", 342 | " transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n", 343 | " ]),\n", 344 | " 'val': transforms.Compose([\n", 345 | " transforms.Resize(256),\n", 346 | " transforms.CenterCrop(224),\n", 347 | " transforms.ToTensor(),\n", 348 | " transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n", 349 | " ]),\n", 350 | " }\n", 351 | "\n", 352 | " image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),\n", 353 | " data_transforms[x])\n", 354 | " for x in ['train', 'val']}\n", 355 | " dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,\n", 356 | " shuffle=True, num_workers=4)\n", 357 | " for x in ['train', 'val']}\n", 358 | " dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}\n", 359 | " class_names = image_datasets['train'].classes\n", 360 | "\n", 361 | " return dataloaders, dataset_sizes, class_names\n", 362 | "\n", 363 | "\n", 364 | "def train_model(model, criterion, optimizer, scheduler, num_epochs, data_dir):\n", 365 | " \"\"\"Train the model.\"\"\"\n", 366 | "\n", 367 | " # load training/validation data\n", 368 | " dataloaders, dataset_sizes, class_names = load_data(data_dir)\n", 369 | "\n", 370 | " device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\n", 371 | "\n", 372 | " since = time.time()\n", 373 | "\n", 374 | " best_model_wts = copy.deepcopy(model.state_dict())\n", 375 | " best_acc = 0.0\n", 376 | "\n", 377 | " for epoch in range(num_epochs):\n", 378 | " print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n", 379 | " print('-' * 10)\n", 380 | "\n", 381 | " # Each epoch has a training and validation phase\n", 382 | " for phase in ['train', 'val']:\n", 383 | " if phase == 'train':\n", 384 | " scheduler.step()\n", 385 | " model.train() # Set model to training mode\n", 386 | " else:\n", 387 | " model.eval() # Set model to evaluate mode\n", 388 | "\n", 389 | " running_loss = 0.0\n", 390 | " running_corrects = 0\n", 391 | "\n", 392 | " # Iterate over data.\n", 393 | " for inputs, labels in dataloaders[phase]:\n", 394 | " inputs = inputs.to(device)\n", 395 | " labels = labels.to(device)\n", 396 | "\n", 397 | " # zero the parameter gradients\n", 398 | " optimizer.zero_grad()\n", 399 | "\n", 400 | " # forward\n", 401 | " # track history if only in train\n", 402 | " with torch.set_grad_enabled(phase == 'train'):\n", 403 | " outputs = model(inputs)\n", 404 | " _, preds = torch.max(outputs, 1)\n", 405 | " loss = criterion(outputs, labels)\n", 406 | "\n", 407 | " # backward + optimize only if in training phase\n", 408 | " if phase == 'train':\n", 409 | " loss.backward()\n", 410 | " optimizer.step()\n", 411 | "\n", 412 | " # statistics\n", 413 | " running_loss += loss.item() * inputs.size(0)\n", 414 | " running_corrects += torch.sum(preds == labels.data)\n", 415 | "\n", 416 | " epoch_loss = running_loss / dataset_sizes[phase]\n", 417 | " epoch_acc = running_corrects.double() / dataset_sizes[phase]\n", 418 | "\n", 419 | " print('{} Loss: {:.4f} Acc: {:.4f}'.format(\n", 420 | " phase, epoch_loss, epoch_acc))\n", 421 | "\n", 422 | " # deep copy the model\n", 423 | " if phase == 'val' and epoch_acc > best_acc:\n", 424 | " best_acc = epoch_acc\n", 425 | " best_model_wts = copy.deepcopy(model.state_dict())\n", 426 | "\n", 427 | " # log the best val accuracy to AML run\n", 428 | " run.log('best_val_acc', np.float(best_acc))\n", 429 | "\n", 430 | " print()\n", 431 | "\n", 432 | " time_elapsed = time.time() - since\n", 433 | " print('Training complete in {:.0f}m {:.0f}s'.format(\n", 434 | " time_elapsed // 60, time_elapsed % 60))\n", 435 | " print('Best val Acc: {:4f}'.format(best_acc))\n", 436 | "\n", 437 | " # load best model weights\n", 438 | " model.load_state_dict(best_model_wts)\n", 439 | " return model\n", 440 | "\n", 441 | "\n", 442 | "def fine_tune_model(num_epochs, data_dir, learning_rate, momentum):\n", 443 | " \"\"\"Load a pretrained model and reset the final fully connected layer.\"\"\"\n", 444 | "\n", 445 | " # log the hyperparameter metrics to the AML run\n", 446 | " run.log('lr', np.float(learning_rate))\n", 447 | " run.log('momentum', np.float(momentum))\n", 448 | "\n", 449 | " model_ft = models.resnet18(pretrained=True)\n", 450 | " num_ftrs = model_ft.fc.in_features\n", 451 | " model_ft.fc = nn.Linear(num_ftrs, 2) # only 2 classes to predict\n", 452 | "\n", 453 | " device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\n", 454 | " model_ft = model_ft.to(device)\n", 455 | "\n", 456 | " criterion = nn.CrossEntropyLoss()\n", 457 | "\n", 458 | " # Observe that all parameters are being optimized\n", 459 | " optimizer_ft = optim.SGD(model_ft.parameters(),\n", 460 | " lr=learning_rate, momentum=momentum)\n", 461 | "\n", 462 | " # Decay LR by a factor of 0.1 every 7 epochs\n", 463 | " exp_lr_scheduler = lr_scheduler.StepLR(\n", 464 | " optimizer_ft, step_size=7, gamma=0.1)\n", 465 | "\n", 466 | " model = train_model(model_ft, criterion, optimizer_ft,\n", 467 | " exp_lr_scheduler, num_epochs, data_dir)\n", 468 | "\n", 469 | " return model\n", 470 | "\n", 471 | "\n", 472 | "def download_data():\n", 473 | " \"\"\"Download and extract the training data.\"\"\"\n", 474 | " import urllib\n", 475 | " from zipfile import ZipFile\n", 476 | " # download data\n", 477 | " data_file = './hymenoptera_data.zip'\n", 478 | " download_url = 'https://download.pytorch.org/tutorial/hymenoptera_data.zip'\n", 479 | " urllib.request.urlretrieve(download_url, filename=data_file)\n", 480 | "\n", 481 | " # extract files\n", 482 | " with ZipFile(data_file, 'r') as zip:\n", 483 | " print('extracting files...')\n", 484 | " zip.extractall()\n", 485 | " print('finished extracting')\n", 486 | " data_dir = zip.namelist()[0]\n", 487 | "\n", 488 | " # delete zip file\n", 489 | " os.remove(data_file)\n", 490 | " return data_dir\n", 491 | "\n", 492 | "\n", 493 | "def main():\n", 494 | " print(\"Torch version:\", torch.__version__)\n", 495 | "\n", 496 | " # get command-line arguments\n", 497 | " parser = argparse.ArgumentParser()\n", 498 | " parser.add_argument('--num_epochs', type=int, default=25,\n", 499 | " help='number of epochs to train')\n", 500 | " parser.add_argument('--output_dir', type=str, help='output directory')\n", 501 | " parser.add_argument('--learning_rate', type=float,\n", 502 | " default=0.001, help='learning rate')\n", 503 | " parser.add_argument('--momentum', type=float, default=0.9, help='momentum')\n", 504 | " args = parser.parse_args()\n", 505 | "\n", 506 | " data_dir = download_data()\n", 507 | " print(\"data directory is: \" + data_dir)\n", 508 | " model = fine_tune_model(args.num_epochs, data_dir,\n", 509 | " args.learning_rate, args.momentum)\n", 510 | " os.makedirs(args.output_dir, exist_ok=True)\n", 511 | " torch.save(model, os.path.join(args.output_dir, 'model.pt'))\n", 512 | "\n", 513 | "\n", 514 | "if __name__ == \"__main__\":\n", 515 | " main()\n", 516 | "\n", 517 | "\n", 518 | "```\n", 519 | "\n", 520 | "こちらのスクリプトの詳細の説明は行いませんが、実行内容としては下記の4ステップになります。 \n", 521 | "\n", 522 | "1. データのダウンロード\n", 523 | "2. 必要な前処理の適応\n", 524 | "3. 学習の実行\n", 525 | "4. 結果の取得" 526 | ] 527 | }, 528 | { 529 | "cell_type": "markdown", 530 | "metadata": {}, 531 | "source": [ 532 | "### Azure MLの学習結果をログに保存\n", 533 | "\n", 534 | "上記のコードにはAzure MLの環境で学習を実行し、結果を追跡するにはいくつかのAzure MLコードが追記されています。 \n", 535 | "詳細は[こちらの公式のドキュメント](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-track-experiments)を確認してください。 \n", 536 | "今回記述されている内容をそれぞれ確認しましょう。 \n", 537 | "\n", 538 | "学習経過には`Azure ML Run`オブジェクトを使用することによってアクセスすることができます。 \n", 539 | "上記のコード内で設定を行なっている部分を確認しましょう。 \n", 540 | "\n", 541 | "```Python\n", 542 | "from azureml.core.run import Run\n", 543 | "run = Run.get_context()\n", 544 | "```\n", 545 | "\n", 546 | "さらに`learning rate`、`momentum`のパラメータ、検証データに対する最高のAccuracy(正解率)のログも取得します。 \n", 547 | "\n", 548 | "```Python\n", 549 | "run.log('lr', np.float(learning_rate))\n", 550 | "run.log('momentum', np.float(momentum))\n", 551 | "\n", 552 | "run.log('best_val_acc', np.float(best_acc))\n", 553 | "```\n", 554 | "\n", 555 | "ハイパーパラメータの調整を行う際にこちらのログは重要な役割を果たします。 \n", 556 | "こちらのスクリプトを先ほど作成した、作業ディレクトリに保存しておきます。 " 557 | ] 558 | }, 559 | { 560 | "cell_type": "code", 561 | "execution_count": 7, 562 | "metadata": {}, 563 | "outputs": [ 564 | { 565 | "data": { 566 | "text/plain": [ 567 | "'./pytorch-hymenoptera/pytorch_train.py'" 568 | ] 569 | }, 570 | "execution_count": 7, 571 | "metadata": {}, 572 | "output_type": "execute_result" 573 | } 574 | ], 575 | "source": [ 576 | "import shutil\n", 577 | "\n", 578 | "shutil.copy('pytorch_train.py', project_folder)" 579 | ] 580 | }, 581 | { 582 | "cell_type": "markdown", 583 | "metadata": {}, 584 | "source": [ 585 | "### Experimentの作成\n", 586 | "ワークスペースですべての実行結果を追跡するために[Experiment](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#experiment) を作成します。 " 587 | ] 588 | }, 589 | { 590 | "cell_type": "code", 591 | "execution_count": 8, 592 | "metadata": {}, 593 | "outputs": [], 594 | "source": [ 595 | "from azureml.core import Experiment\n", 596 | "\n", 597 | "experiment_name = 'pytorch-hymenoptera'\n", 598 | "experiment = Experiment(ws, name=experiment_name)" 599 | ] 600 | }, 601 | { 602 | "cell_type": "markdown", 603 | "metadata": {}, 604 | "source": [ 605 | "### PyTorch estimatorの作成\n", 606 | "\n", 607 | "Azure ML SDKのPyTorch estimatorを使用すると、単一ノードと分散の両方の実行について、PyTorchトレーニングジョブを簡単に送信できます。 \n", 608 | "PyTorch estimatorの詳細については、[こちら](https://docs.microsoft.com/azure/machine-learning/service/how-to-train-pytorch)を参照してください。次のコードは単一ノードのPyTorchジョブを定義します。" 609 | ] 610 | }, 611 | { 612 | "cell_type": "code", 613 | "execution_count": 10, 614 | "metadata": {}, 615 | "outputs": [], 616 | "source": [ 617 | "from azureml.train.dnn import PyTorch\n", 618 | "\n", 619 | "script_params = {\n", 620 | " '--num_epochs': 30,\n", 621 | " '--output_dir': './outputs'\n", 622 | "}\n", 623 | "\n", 624 | "estimator = PyTorch(source_directory=project_folder, \n", 625 | " script_params=script_params,\n", 626 | " compute_target=compute_target,\n", 627 | " entry_script='pytorch_train.py',\n", 628 | " use_gpu=True)" 629 | ] 630 | }, 631 | { 632 | "cell_type": "markdown", 633 | "metadata": {}, 634 | "source": [ 635 | "`scripti_params`に訓練に必要な引数を渡す必要があります。  \n", 636 | "\n", 637 | "\n", 638 | "#### script_params\n", 639 | "\n", 640 | "`script_params`は` entry_script`で指定しているスクリプトに必要な引数を渡す辞書型のオブジェクトです。 \n", 641 | "今回の設定は下記になります。 \n", 642 | "- `--num_epochs`:`30`→エポック数を30に設定\n", 643 | "- `'--output_dir': './outputs'`→学習の実行履歴を保存するディレクトリの指定\n", 644 | "\n", 645 | "この出力ディレクトリである `./ output`はAzure ML上で特別に扱われます。 \n", 646 | "このディレクトリ内の情報は全て実行履歴の一部としてワークスペースにアップロードされ、リモート実行が終了してもアクセス可能です。\n", 647 | "\n", 648 | "#### データストアからデータの読み込み\n", 649 | "\n", 650 | "訓練時にデータを読み込む必要がある場合はデータストアと呼ばれる場所にデータをUploadし、そこからデータを読み込む必要があります。 \n", 651 | "その方法については[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-access-data)を確認してください。 \n", 652 | "(データストアはワークスペースのリソースを作成した段階で使用可能になります。) \n", 653 | "\n", 654 | "\n", 655 | "#### GPUの使用\n", 656 | "\n", 657 | "Azure VMのGPUをトレーニングに活用するには、`use_gpu = True`に設定します。" 658 | ] 659 | }, 660 | { 661 | "cell_type": "markdown", 662 | "metadata": {}, 663 | "source": [ 664 | "### ジョブの実行\n", 665 | "\n", 666 | "Estimatorオブジェクトを送信してExperimentを実行します。 \n", 667 | "この実行は非同期です。" 668 | ] 669 | }, 670 | { 671 | "cell_type": "code", 672 | "execution_count": 11, 673 | "metadata": {}, 674 | "outputs": [ 675 | { 676 | "name": "stdout", 677 | "output_type": "stream", 678 | "text": [ 679 | "Run(Experiment: pytorch-hymenoptera,\n", 680 | "Id: pytorch-hymenoptera_1548675415501,\n", 681 | "Type: azureml.scriptrun,\n", 682 | "Status: Queued)\n" 683 | ] 684 | } 685 | ], 686 | "source": [ 687 | "run = experiment.submit(estimator)\n", 688 | "print(run)" 689 | ] 690 | }, 691 | { 692 | "cell_type": "code", 693 | "execution_count": 12, 694 | "metadata": {}, 695 | "outputs": [ 696 | { 697 | "name": "stdout", 698 | "output_type": "stream", 699 | "text": [ 700 | "{'runId': 'pytorch-hymenoptera_1548675415501', 'target': 'gpucluster', 'status': 'Queued', 'properties': {'azureml.runsource': 'experiment', 'ContentSnapshotId': 'ee1c7a9d-7148-477d-90f3-cbbfe520088a'}, 'runDefinition': {'Script': 'pytorch_train.py', 'Arguments': ['--num_epochs', '30', '--output_dir', './outputs'], 'SourceDirectoryDataStore': None, 'Framework': 0, 'Communicator': 0, 'Target': 'gpucluster', 'DataReferences': {}, 'JobName': None, 'AutoPrepareEnvironment': True, 'MaxRunDurationSeconds': None, 'NodeCount': 1, 'Environment': {'Python': {'InterpreterPath': 'python', 'UserManagedDependencies': False, 'CondaDependencies': {'name': 'project_environment', 'dependencies': ['python=3.6.2', {'pip': ['azureml-defaults', 'torch==1.0.0', 'torchvision==0.2.1']}]}}, 'EnvironmentVariables': {'EXAMPLE_ENV_VAR': 'EXAMPLE_VALUE', 'NCCL_SOCKET_IFNAME': '^docker0'}, 'Docker': {'BaseImage': 'mcr.microsoft.com/azureml/base-gpu:0.2.1', 'Enabled': True, 'SharedVolumes': True, 'Preparation': None, 'GpuSupport': True, 'ShmSize': '1g', 'Arguments': [], 'BaseImageRegistry': {'Address': None, 'Username': None, 'Password': None}}, 'Spark': {'Repositories': ['https://mmlspark.azureedge.net/maven'], 'Packages': [{'Group': 'com.microsoft.ml.spark', 'Artifact': 'mmlspark_2.11', 'Version': '0.12'}], 'PrecachePackages': True}}, 'History': {'OutputCollection': True}, 'Spark': {'Configuration': {'spark.app.name': 'Azure ML Experiment', 'spark.yarn.maxAppAttempts': '1'}}, 'BatchAi': {'NodeCount': 0}, 'AmlCompute': {'Name': None, 'VmSize': None, 'VmPriority': None, 'RetainCluster': False, 'ClusterMaxNodeCount': 1}, 'Tensorflow': {'WorkerCount': 1, 'ParameterServerCount': 1}, 'Mpi': {'ProcessCountPerNode': 1}, 'Hdi': {'YarnDeployMode': 2}, 'ContainerInstance': {'Region': None, 'CpuCores': 0, 'MemoryGb': 0}, 'ExposedPorts': None, 'PrepareEnvironment': None}, 'logFiles': {}}\n" 701 | ] 702 | } 703 | ], 704 | "source": [ 705 | "# to get more details of your run\n", 706 | "print(run.get_details())" 707 | ] 708 | }, 709 | { 710 | "cell_type": "markdown", 711 | "metadata": {}, 712 | "source": [ 713 | "### 実行経過の確認\n", 714 | "\n", 715 | "Jupyter Notebookのウィジェットを使用して実行の進行状況を監視できます。 \n", 716 | "実行依頼と同様に、ウィジェットは非同期で、ジョブが完了するまで10〜15秒ごとにライブアップデートを行います。 " 717 | ] 718 | }, 719 | { 720 | "cell_type": "code", 721 | "execution_count": 13, 722 | "metadata": {}, 723 | "outputs": [ 724 | { 725 | "data": { 726 | "application/vnd.jupyter.widget-view+json": { 727 | "model_id": "27aa2d859f0c4dd7ae1dfee074754a4d", 728 | "version_major": 2, 729 | "version_minor": 0 730 | }, 731 | "text/plain": [ 732 | "_UserRunWidget(widget_settings={'childWidgetDisplay': 'popup', 'send_telemetry': True, 'log_level': 'INFO', 's…" 733 | ] 734 | }, 735 | "metadata": {}, 736 | "output_type": "display_data" 737 | } 738 | ], 739 | "source": [ 740 | "from azureml.widgets import RunDetails\n", 741 | "\n", 742 | "RunDetails(run).show()" 743 | ] 744 | }, 745 | { 746 | "cell_type": "markdown", 747 | "metadata": {}, 748 | "source": [ 749 | "また、スクリプトがトレーニングを完了するまでブロックしてから、学習結果を確認することも可能です。" 750 | ] 751 | }, 752 | { 753 | "cell_type": "code", 754 | "execution_count": 14, 755 | "metadata": {}, 756 | "outputs": [ 757 | { 758 | "name": "stdout", 759 | "output_type": "stream", 760 | "text": [ 761 | "RunId: pytorch-hymenoptera_1548675415501\n", 762 | "\n", 763 | "Execution Summary\n", 764 | "=================\n", 765 | "RunId: pytorch-hymenoptera_1548675415501\n", 766 | "\n" 767 | ] 768 | }, 769 | { 770 | "data": { 771 | "text/plain": [ 772 | "{'runId': 'pytorch-hymenoptera_1548675415501',\n", 773 | " 'target': 'gpucluster',\n", 774 | " 'status': 'Completed',\n", 775 | " 'startTimeUtc': '2019-01-28T11:41:54.927543Z',\n", 776 | " 'endTimeUtc': '2019-01-28T11:54:18.579572Z',\n", 777 | " 'properties': {'azureml.runsource': 'experiment',\n", 778 | " 'ContentSnapshotId': 'ee1c7a9d-7148-477d-90f3-cbbfe520088a'},\n", 779 | " 'runDefinition': {'Script': 'pytorch_train.py',\n", 780 | " 'Arguments': ['--num_epochs', '30', '--output_dir', './outputs'],\n", 781 | " 'SourceDirectoryDataStore': None,\n", 782 | " 'Framework': 0,\n", 783 | " 'Communicator': 0,\n", 784 | " 'Target': 'gpucluster',\n", 785 | " 'DataReferences': {},\n", 786 | " 'JobName': None,\n", 787 | " 'AutoPrepareEnvironment': True,\n", 788 | " 'MaxRunDurationSeconds': None,\n", 789 | " 'NodeCount': 1,\n", 790 | " 'Environment': {'Python': {'InterpreterPath': 'python',\n", 791 | " 'UserManagedDependencies': False,\n", 792 | " 'CondaDependencies': {'name': 'project_environment',\n", 793 | " 'dependencies': ['python=3.6.2',\n", 794 | " {'pip': ['azureml-defaults', 'torch==1.0.0', 'torchvision==0.2.1']}]}},\n", 795 | " 'EnvironmentVariables': {'EXAMPLE_ENV_VAR': 'EXAMPLE_VALUE',\n", 796 | " 'NCCL_SOCKET_IFNAME': '^docker0'},\n", 797 | " 'Docker': {'BaseImage': 'mcr.microsoft.com/azureml/base-gpu:0.2.1',\n", 798 | " 'Enabled': True,\n", 799 | " 'SharedVolumes': True,\n", 800 | " 'Preparation': None,\n", 801 | " 'GpuSupport': True,\n", 802 | " 'ShmSize': '1g',\n", 803 | " 'Arguments': [],\n", 804 | " 'BaseImageRegistry': {'Address': None,\n", 805 | " 'Username': None,\n", 806 | " 'Password': None}},\n", 807 | " 'Spark': {'Repositories': ['https://mmlspark.azureedge.net/maven'],\n", 808 | " 'Packages': [{'Group': 'com.microsoft.ml.spark',\n", 809 | " 'Artifact': 'mmlspark_2.11',\n", 810 | " 'Version': '0.12'}],\n", 811 | " 'PrecachePackages': True}},\n", 812 | " 'History': {'OutputCollection': True},\n", 813 | " 'Spark': {'Configuration': {'spark.app.name': 'Azure ML Experiment',\n", 814 | " 'spark.yarn.maxAppAttempts': '1'}},\n", 815 | " 'BatchAi': {'NodeCount': 0},\n", 816 | " 'AmlCompute': {'Name': None,\n", 817 | " 'VmSize': None,\n", 818 | " 'VmPriority': None,\n", 819 | " 'RetainCluster': False,\n", 820 | " 'ClusterMaxNodeCount': 1},\n", 821 | " 'Tensorflow': {'WorkerCount': 1, 'ParameterServerCount': 1},\n", 822 | " 'Mpi': {'ProcessCountPerNode': 1},\n", 823 | " 'Hdi': {'YarnDeployMode': 2},\n", 824 | " 'ContainerInstance': {'Region': None, 'CpuCores': 0, 'MemoryGb': 0},\n", 825 | " 'ExposedPorts': None,\n", 826 | " 'PrepareEnvironment': None},\n", 827 | " 'logFiles': {'azureml-logs/60_control_log.txt': 'https://dllabazureml5427306140.blob.core.windows.net/azureml/ExperimentRun/dcid.pytorch-hymenoptera_1548675415501/azureml-logs/60_control_log.txt?sv=2018-03-28&sr=b&sig=A8YxZGBACIWAJ4YnM0uyy45cuTakXNcEULYkLQ6MxRk%3D&st=2019-01-28T11%3A45%3A50Z&se=2019-01-28T19%3A55%3A50Z&sp=r',\n", 828 | " 'azureml-logs/80_driver_log.txt': 'https://dllabazureml5427306140.blob.core.windows.net/azureml/ExperimentRun/dcid.pytorch-hymenoptera_1548675415501/azureml-logs/80_driver_log.txt?sv=2018-03-28&sr=b&sig=FuOM6Gk91EIbUumaYqliPP78ZEaqGqeCno3N2BIF8Mw%3D&st=2019-01-28T11%3A45%3A50Z&se=2019-01-28T19%3A55%3A50Z&sp=r',\n", 829 | " 'azureml-logs/azureml.log': 'https://dllabazureml5427306140.blob.core.windows.net/azureml/ExperimentRun/dcid.pytorch-hymenoptera_1548675415501/azureml-logs/azureml.log?sv=2018-03-28&sr=b&sig=JOuG4y0OxLCK2mE9kp1qwTrc3p9IkRVuqitee0KsUEU%3D&st=2019-01-28T11%3A45%3A50Z&se=2019-01-28T19%3A55%3A50Z&sp=r',\n", 830 | " 'azureml-logs/55_batchai_execution.txt': 'https://dllabazureml5427306140.blob.core.windows.net/azureml/ExperimentRun/dcid.pytorch-hymenoptera_1548675415501/azureml-logs/55_batchai_execution.txt?sv=2018-03-28&sr=b&sig=IL3%2FVaufLHdIqlVrJ4rXVWkTxPRWkYa6VAjYon3cVzA%3D&st=2019-01-28T11%3A45%3A50Z&se=2019-01-28T19%3A55%3A50Z&sp=r'}}" 831 | ] 832 | }, 833 | "execution_count": 14, 834 | "metadata": {}, 835 | "output_type": "execute_result" 836 | } 837 | ], 838 | "source": [ 839 | "run.wait_for_completion(show_output=True)" 840 | ] 841 | }, 842 | { 843 | "cell_type": "markdown", 844 | "metadata": {}, 845 | "source": [ 846 | "## 学習済みモデルのデプロイ\n", 847 | "\n", 848 | "学習済みモデルが作成できました。 \n", 849 | "続いてそのモデルをAzureにデプロイします。 \n", 850 | "今回はモデルを[Azure Container Instances](https://docs.microsoft.com/en-us/azure/container-instances/)(ACI)にWebサービスとしてデプロイします。 \n", 851 | "Azure MLを使用してモデルを展開する方法の詳細については、[こちら](https://docs.microsoft.com/azure/machine-learning/service/how-to-deploy-and-where)を参照してください。" 852 | ] 853 | }, 854 | { 855 | "cell_type": "markdown", 856 | "metadata": {}, 857 | "source": [ 858 | "### 学習済みモデルの保存\n", 859 | "\n", 860 | "`run.register_model`を使用すると学習済みモデルを保存することが可能です。 " 861 | ] 862 | }, 863 | { 864 | "cell_type": "code", 865 | "execution_count": 23, 866 | "metadata": {}, 867 | "outputs": [ 868 | { 869 | "name": "stdout", 870 | "output_type": "stream", 871 | "text": [ 872 | "pytorch-hymenoptera\tpytorch-hymenoptera:1\t1\n" 873 | ] 874 | } 875 | ], 876 | "source": [ 877 | "model = run.register_model(model_name='pytorch-hymenoptera', model_path='outputs/model.pt')\n", 878 | "print(model.name, model.id, model.version, sep = '\\t')" 879 | ] 880 | }, 881 | { 882 | "cell_type": "markdown", 883 | "metadata": {}, 884 | "source": [ 885 | "### スコアリングスクリプトの作成\n", 886 | "\n", 887 | "まず、Webサービスに呼び出されるスコアリングスクリプトを作成します。 \n", 888 | "スコアリングスクリプトには、2つの関数が必要になります。\n", 889 | "\n", 890 | "- `init()`:この関数では、通常モデルを `global`オブジェクトにロードします。この関数はDockerコンテナが起動されたときに一度だけ実行されます。\n", 891 | "- `run(input_data)`:この関数では、新たな入力データ対して学習済みモデルを使用して推論を実行します。通常は入力と出力は通常シリアライゼーションとデシリアライゼーションのフォーマットとしてJSONを使用しますが、他のフォーマットも使用することが可能です。\n", 892 | "\n", 893 | "今回は準備されている`pytorch_score.py`を使用します。 \n", 894 | "また用意されているテスト用の画像ファイルを使用して推論を実行します。 \n", 895 | "独自のスコアリングスクリプトを書くときは、Webサービスを実行する前にまずローカルでテストすることを忘れないでください。 \n", 896 | "\n", 897 | "使用するスクリプトは下記になります。 \n", 898 | "\n", 899 | "```python\n", 900 | "\n", 901 | "import torch\n", 902 | "import torch.nn as nn\n", 903 | "from torchvision import transforms\n", 904 | "import json\n", 905 | "\n", 906 | "from azureml.core.model import Model\n", 907 | "\n", 908 | "\n", 909 | "def init():\n", 910 | " global model\n", 911 | " model_path = Model.get_model_path('pytorch-hymenoptera')\n", 912 | " model = torch.load(model_path, map_location=lambda storage, loc: storage)\n", 913 | " model.eval()\n", 914 | "\n", 915 | "\n", 916 | "def run(input_data):\n", 917 | " input_data = torch.tensor(json.loads(input_data)['data'])\n", 918 | "\n", 919 | " # get prediction\n", 920 | " with torch.no_grad():\n", 921 | " output = model(input_data)\n", 922 | " classes = ['ants', 'bees']\n", 923 | " softmax = nn.Softmax(dim=1)\n", 924 | " pred_probs = softmax(output).numpy()[0]\n", 925 | " index = torch.argmax(output, 1)\n", 926 | "\n", 927 | " result = {\"label\": classes[index], \"probability\": str(pred_probs[index])}\n", 928 | " return result\n", 929 | "\n", 930 | "```" 931 | ] 932 | }, 933 | { 934 | "cell_type": "markdown", 935 | "metadata": {}, 936 | "source": [ 937 | "### 環境ファイルを作成する\n", 938 | "\n", 939 | "スコアリングスクリプトのすべてのパッケージ依存関係を指定する環境ファイル( `myenv.yml`)を作成する必要があります。このファイルは、Azure MLによってこれらのすべての依存関係がDockerイメージにインストールされるようにするために使用されます。この場合、 `azureml-core`、` torch`、そして `torchvision`が必要になります。" 940 | ] 941 | }, 942 | { 943 | "cell_type": "code", 944 | "execution_count": 16, 945 | "metadata": {}, 946 | "outputs": [ 947 | { 948 | "name": "stdout", 949 | "output_type": "stream", 950 | "text": [ 951 | "# Conda environment specification. The dependencies defined in this file will\r\n", 952 | "# be automatically provisioned for runs with userManagedDependencies=False.\r\n", 953 | "\n", 954 | "# Details about the Conda environment file format:\r\n", 955 | "# https://conda.io/docs/user-guide/tasks/manage-environments.html#create-env-file-manually\r\n", 956 | "\n", 957 | "name: project_environment\n", 958 | "dependencies:\n", 959 | " # The python interpreter version.\r\n", 960 | " # Currently Azure ML only supports 3.5.2 and later.\r\n", 961 | "- python=3.6.2\n", 962 | "\n", 963 | "- pip:\n", 964 | " - azureml-defaults==1.0.8\n", 965 | " - torch\n", 966 | " - torchvision\n", 967 | "\n" 968 | ] 969 | } 970 | ], 971 | "source": [ 972 | "from azureml.core.conda_dependencies import CondaDependencies \n", 973 | "\n", 974 | "myenv = CondaDependencies.create(pip_packages=['azureml-defaults', 'torch', 'torchvision'])\n", 975 | "\n", 976 | "with open(\"myenv.yml\",\"w\") as f:\n", 977 | " f.write(myenv.serialize_to_string())\n", 978 | " \n", 979 | "print(myenv.serialize_to_string())" 980 | ] 981 | }, 982 | { 983 | "cell_type": "markdown", 984 | "metadata": {}, 985 | "source": [ 986 | "### Dockerイメージの設定\n", 987 | "\n", 988 | "ACIコンテナーを構築するために使用するDockerイメージを構成します。 \n", 989 | "詳細については[こちらの公式ドキュメント](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.image.containerimage?view=azure-ml-py)を確認してください。 " 990 | ] 991 | }, 992 | { 993 | "cell_type": "code", 994 | "execution_count": 17, 995 | "metadata": {}, 996 | "outputs": [], 997 | "source": [ 998 | "from azureml.core.image import ContainerImage\n", 999 | "\n", 1000 | "image_config = ContainerImage.image_configuration(execution_script='pytorch_score.py', \n", 1001 | " runtime='python', \n", 1002 | " conda_file='myenv.yml',\n", 1003 | " description='Image with hymenoptera model')" 1004 | ] 1005 | }, 1006 | { 1007 | "cell_type": "markdown", 1008 | "metadata": {}, 1009 | "source": [ 1010 | "### ACIコンテナの設定\n", 1011 | "\n", 1012 | "デプロイのための準備がほぼ整いました。 \n", 1013 | "ACIコンテナに必要なCPUの数とギガバイトのRAMを指定するためのデプロイメント構成ファイルを作成します。 \n", 1014 | "それは作成したモデルに依存しますが、一般的なモデルではデフォルトの `1`コアと` 1`ギガバイトのRAMで十分なケースが多いです。 " 1015 | ] 1016 | }, 1017 | { 1018 | "cell_type": "code", 1019 | "execution_count": 18, 1020 | "metadata": {}, 1021 | "outputs": [], 1022 | "source": [ 1023 | "from azureml.core.webservice import AciWebservice\n", 1024 | "\n", 1025 | "aciconfig = AciWebservice.deploy_configuration(cpu_cores=1, \n", 1026 | " memory_gb=1, \n", 1027 | " tags={'data': 'hymenoptera', 'method':'transfer learning', 'framework':'pytorch'},\n", 1028 | " description='Classify ants/bees using transfer learning with PyTorch')" 1029 | ] 1030 | }, 1031 | { 1032 | "cell_type": "markdown", 1033 | "metadata": {}, 1034 | "source": [ 1035 | "### Container Instances にデプロイする\n", 1036 | "\n", 1037 | "最後に、登録したモデルからWebサービスをデプロイしましょう。 \n", 1038 | "前の手順で作成したACI設定ファイルとイメージ設定ファイルを使用してWebサービスをデプロイします。 \n", 1039 | "\n", 1040 | "リストの中の `model`オブジェクトを` models`パラメータに渡します。 \n", 1041 | "複数の登録済みモデルをデプロイする場合は、このリストに他のモデルを追加してください。  " 1042 | ] 1043 | }, 1044 | { 1045 | "cell_type": "code", 1046 | "execution_count": 24, 1047 | "metadata": {}, 1048 | "outputs": [ 1049 | { 1050 | "name": "stdout", 1051 | "output_type": "stream", 1052 | "text": [ 1053 | "Creating image\n", 1054 | "Image creation operation finished for image aci-hymenoptera:2, operation \"Succeeded\"\n", 1055 | "Creating service\n", 1056 | "Running........................\n", 1057 | "SucceededACI service creation operation finished, operation \"Succeeded\"\n", 1058 | "Healthy\n", 1059 | "CPU times: user 7.82 s, sys: 696 ms, total: 8.51 s\n", 1060 | "Wall time: 8min 2s\n" 1061 | ] 1062 | } 1063 | ], 1064 | "source": [ 1065 | "%%time\n", 1066 | "from azureml.core.webservice import Webservice\n", 1067 | "\n", 1068 | "service_name = 'aci-hymenoptera'\n", 1069 | "service = Webservice.deploy_from_model(workspace=ws,\n", 1070 | " name=service_name,\n", 1071 | " models=[model],\n", 1072 | " image_config=image_config,\n", 1073 | " deployment_config=aciconfig,)\n", 1074 | "\n", 1075 | "service.wait_for_deployment(show_output=True)\n", 1076 | "print(service.state)" 1077 | ] 1078 | }, 1079 | { 1080 | "cell_type": "markdown", 1081 | "metadata": {}, 1082 | "source": [ 1083 | "通常デプロイには7~8分かかります。 \n", 1084 | "下記のように表示されればデプロイが成功しています。 \n", 1085 | "\n", 1086 | "```\n", 1087 | "SucceededACI service creation operation finished, operation \"Succeeded\"\n", 1088 | "\n", 1089 | "```\n", 1090 | "\n", 1091 | "#### デプロイがうまくいかない場合\n", 1092 | "\n", 1093 | "もし、何らかの理由でデプロイが失敗して再デプロイする必要がある場合は、必ずサービスを`service.delete()`で削除してください。 \n", 1094 | "\n", 1095 | "**また、デプロイに問題が発生した場合、まず下記のコマンドを実行して、サービスからログを取得しましょう。**" 1096 | ] 1097 | }, 1098 | { 1099 | "cell_type": "code", 1100 | "execution_count": null, 1101 | "metadata": {}, 1102 | "outputs": [], 1103 | "source": [ 1104 | "service.get_logs()" 1105 | ] 1106 | }, 1107 | { 1108 | "cell_type": "markdown", 1109 | "metadata": {}, 1110 | "source": [ 1111 | "RESTクライアント呼び出しを受け付けるWebサービスのHTTPエンドポイントを取得します。 \n", 1112 | "このエンドポイントは、Webサービスをテストしたい、またはそれをアプリケーションに統合したい人と共有することができます。" 1113 | ] 1114 | }, 1115 | { 1116 | "cell_type": "code", 1117 | "execution_count": 28, 1118 | "metadata": {}, 1119 | "outputs": [ 1120 | { 1121 | "name": "stdout", 1122 | "output_type": "stream", 1123 | "text": [ 1124 | "http://104.45.171.246:80/score\n" 1125 | ] 1126 | } 1127 | ], 1128 | "source": [ 1129 | "print(service.scoring_uri)" 1130 | ] 1131 | }, 1132 | { 1133 | "cell_type": "markdown", 1134 | "metadata": {}, 1135 | "source": [ 1136 | "## デプロイされたサービスをテストする\n", 1137 | "\n", 1138 | "最後に、デプロイしたWebサービスをテストしましょう。 \n", 1139 | "データをJSON文字列としてACIでホストされているWebサービスに送信し、SDKの `run` APIを使用してサービスを呼び出します。 \n", 1140 | "ここで、検証データからイメージを取得して推論を実行します。" 1141 | ] 1142 | }, 1143 | { 1144 | "cell_type": "code", 1145 | "execution_count": 25, 1146 | "metadata": {}, 1147 | "outputs": [ 1148 | { 1149 | "data": { 1150 | "text/plain": [ 1151 | "" 1152 | ] 1153 | }, 1154 | "execution_count": 25, 1155 | "metadata": {}, 1156 | "output_type": "execute_result" 1157 | } 1158 | ], 1159 | "source": [ 1160 | "import os, json\n", 1161 | "from PIL import Image\n", 1162 | "import matplotlib.pyplot as plt\n", 1163 | "\n", 1164 | "plt.imshow(Image.open('test_img.jpg'))" 1165 | ] 1166 | }, 1167 | { 1168 | "cell_type": "markdown", 1169 | "metadata": {}, 1170 | "source": [ 1171 | "画像データに対して学習時と同じ前処理を適応し、推論が実行できる状態に変更します。 " 1172 | ] 1173 | }, 1174 | { 1175 | "cell_type": "code", 1176 | "execution_count": 26, 1177 | "metadata": {}, 1178 | "outputs": [], 1179 | "source": [ 1180 | "import torch\n", 1181 | "from torchvision import transforms\n", 1182 | " \n", 1183 | "def preprocess(image_file):\n", 1184 | " \"\"\"Preprocess the input image.\"\"\"\n", 1185 | " data_transforms = transforms.Compose([\n", 1186 | " transforms.Resize(256),\n", 1187 | " transforms.CenterCrop(224),\n", 1188 | " transforms.ToTensor(),\n", 1189 | " transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n", 1190 | " ])\n", 1191 | "\n", 1192 | " image = Image.open(image_file)\n", 1193 | " image = data_transforms(image).float()\n", 1194 | " image = torch.tensor(image)\n", 1195 | " image = image.unsqueeze(0)\n", 1196 | " return image.numpy()" 1197 | ] 1198 | }, 1199 | { 1200 | "cell_type": "markdown", 1201 | "metadata": {}, 1202 | "source": [ 1203 | "デプロイしたAPIを使用して推論を実行します。 " 1204 | ] 1205 | }, 1206 | { 1207 | "cell_type": "code", 1208 | "execution_count": 27, 1209 | "metadata": {}, 1210 | "outputs": [ 1211 | { 1212 | "name": "stdout", 1213 | "output_type": "stream", 1214 | "text": [ 1215 | "{'label': 'bees', 'probability': '0.999579'}\n" 1216 | ] 1217 | } 1218 | ], 1219 | "source": [ 1220 | "input_data = preprocess('test_img.jpg')\n", 1221 | "result = service.run(input_data=json.dumps({'data': input_data.tolist()}))\n", 1222 | "print(result)" 1223 | ] 1224 | }, 1225 | { 1226 | "cell_type": "markdown", 1227 | "metadata": {}, 1228 | "source": [ 1229 | "うまく推論ができていることが確認できました。 \n", 1230 | "このデプロイされたモデルに関してはAzure Portalの「デプロイ」タブから詳細情報について確認することができます。 \n", 1231 | "\n", 1232 | "これでAzure Machine Learningの基礎的な使用方法が理解できました。 " 1233 | ] 1234 | }, 1235 | { 1236 | "cell_type": "markdown", 1237 | "metadata": {}, 1238 | "source": [ 1239 | "## 後片付け\n", 1240 | "\n", 1241 | "Webサービスが不要になったら、API呼び出しで簡単に削除できます。" 1242 | ] 1243 | }, 1244 | { 1245 | "cell_type": "code", 1246 | "execution_count": 29, 1247 | "metadata": {}, 1248 | "outputs": [], 1249 | "source": [ 1250 | "service.delete()" 1251 | ] 1252 | }, 1253 | { 1254 | "cell_type": "markdown", 1255 | "metadata": {}, 1256 | "source": [ 1257 | "続いては一緒に手持ちのデータを使用して学習を行う方法を確認します。 \n", 1258 | "また今回は行わなかったハイパーパラメータの調整方法もご紹介します。 " 1259 | ] 1260 | } 1261 | ], 1262 | "metadata": { 1263 | "authors": [ 1264 | { 1265 | "name": "minxia" 1266 | } 1267 | ], 1268 | "kernelspec": { 1269 | "display_name": "Python 3", 1270 | "language": "python", 1271 | "name": "python3" 1272 | }, 1273 | "language_info": { 1274 | "codemirror_mode": { 1275 | "name": "ipython", 1276 | "version": 3 1277 | }, 1278 | "file_extension": ".py", 1279 | "mimetype": "text/x-python", 1280 | "name": "python", 1281 | "nbconvert_exporter": "python", 1282 | "pygments_lexer": "ipython3", 1283 | "version": "3.6.4" 1284 | }, 1285 | "msauthor": "minxia" 1286 | }, 1287 | "nbformat": 4, 1288 | "nbformat_minor": 2 1289 | } 1290 | -------------------------------------------------------------------------------- /docs/data/dog-cat.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepLearningLab/AML-Handson/890ec2bc012a78299a74bf05c8bcc0d6d4bd9cf2/docs/data/dog-cat.zip -------------------------------------------------------------------------------- /docs/data/test_img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepLearningLab/AML-Handson/890ec2bc012a78299a74bf05c8bcc0d6d4bd9cf2/docs/data/test_img.jpg -------------------------------------------------------------------------------- /docs/data/test_img2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepLearningLab/AML-Handson/890ec2bc012a78299a74bf05c8bcc0d6d4bd9cf2/docs/data/test_img2.jpeg -------------------------------------------------------------------------------- /docs/images/02_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepLearningLab/AML-Handson/890ec2bc012a78299a74bf05c8bcc0d6d4bd9cf2/docs/images/02_01.png -------------------------------------------------------------------------------- /docs/images/02_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepLearningLab/AML-Handson/890ec2bc012a78299a74bf05c8bcc0d6d4bd9cf2/docs/images/02_02.png -------------------------------------------------------------------------------- /docs/images/02_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepLearningLab/AML-Handson/890ec2bc012a78299a74bf05c8bcc0d6d4bd9cf2/docs/images/02_03.png -------------------------------------------------------------------------------- /docs/images/02_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepLearningLab/AML-Handson/890ec2bc012a78299a74bf05c8bcc0d6d4bd9cf2/docs/images/02_04.png -------------------------------------------------------------------------------- /img/iotedge01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepLearningLab/AML-Handson/890ec2bc012a78299a74bf05c8bcc0d6d4bd9cf2/img/iotedge01.jpg -------------------------------------------------------------------------------- /img/iotedge02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepLearningLab/AML-Handson/890ec2bc012a78299a74bf05c8bcc0d6d4bd9cf2/img/iotedge02.jpg -------------------------------------------------------------------------------- /ppt/AzureMachineLearningServicesHOL.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DeepLearningLab/AML-Handson/890ec2bc012a78299a74bf05c8bcc0d6d4bd9cf2/ppt/AzureMachineLearningServicesHOL.pptx --------------------------------------------------------------------------------