# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # Azure MLで学習済みモデルの作成からデプロイまで
#
# このチュートリアルでは、`Azure Machine Learning（Azure ML）Python SDK`を使用して、  
# モデルのトレーニング、ハイパーパラメーターの調整、およびデプロイを行います。  
# ※ディープラーニングのフレームワークには`PyTorch`を使用します。  
#
#
# 問題設定は[Transfer Learningチュートリアル](https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html)から、  Transfer Learning（転移学習）を使用してアリとハチの画像分類になります。  
#
# *転移学習とは？*  
# 転移学習とは学習済みモデルを使用して（ネットワークの構造と重みの再利用）、学習を行うことをさします。  
# 類似のものとしてファインチューニングがありますが、学習済みモデルのネットワークの学習を行うのがファインチューニングになります。  
# 転移学習では学習済みモデルのネットワーク自体の学習は行いません。（出力前の全結合層のみを学習させるのが一般的）  

# ## 環境構築
#
# 環境は「[Azure Machine Learning Services](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/) ワークスペース」にある`Azure Notebooks`を使用します。  
# Pythonの実行環境や、Azure ML Servicesを使用に必要な[Azure ML Python SDK](https://docs.microsoft.com/ja-jp/python/api/overview/azure/ml/intro?view=azure-ml-py)は既にインストールされています。　  
#
# では、まずは[Azure Portal](https://azure.microsoft.com/ja-jp/features/azure-portal/)を開いて、`Azure Notebooks`の準備を行いましょう。  
# 今回は解説しませんがローカル環境で行う際には[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/quickstart-create-workspace-with-python)を参照してください。  
#
#
# ### リソースの作成
#
# まずは作業を行うためにAzure Machine Learning Services ワークスペースのリソースを作成します。  
# 作成方法は[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/quickstart-get-started)を確認してください。  

# ### バージョンの確認

# +
# Check core SDK version number
import azureml.core

print("SDK version:", azureml.core.VERSION)
# -

# AzrueML上では既にAzureML Python SDKが準備されているため、インストールする必要はありません。  

# ### ワークスペースの初期化
#
# [ワークスペース](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#workspace)の初期化を行います。  
# `Workspace.from_config()`は`config.json`ファイルを参照してワークスペースを初期化します。  
#
# #### configファイルの編集
#
# `config.json`ファイルは基本的に自動でこのように設定を反映されます。  
# 自身で設定する際には下記のように編集します。  
#
# ```json
#
# {
#     "subscription_id": "サブスクリプションID",
#     "resource_group": "リソースグループ名",
#     "workspace_name": "ワークスペース名"
# }
#
# ```
#
# 上記の情報はAzure Portalの画面から確認することができます。  
# では、実行して、ワークスペースの初期化を行います。  
#
# 初期化を行う時に、サインインを要求されるので、表示されるコードをコピーして、URLをクリックします。  
# 遷移先の画面でコピーしたコードを入力することによって、サインインが完了します。  

# +
from azureml.core.workspace import Workspace

ws = Workspace.from_config()
print('Workspace name: ' + ws.name, 
      'Azure region: ' + ws.location, 
      'Resource group: ' + ws.resource_group, sep = '\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))を使用します。  
# （コンピューティングターゲットは計算を実行する場所を決定するようなイメージです。）
#
# ※AmlComputeの作成には約5分かかります。  
# その名前のAmlComputeが既にワークスペースにある場合、このコードは作成プロセスをスキップします。
#
#
# 他のAzureサービスと同様に、Azure Machine Learningサービスに関連する特定のリソース（AmlComputeなど）には制限があります。  
# デフォルトの制限と、より多くのクォータを要求する方法についての[この記事](https://docs.microsoft.com/en-us/azure/machine-learning/service/how-to-manage-quotas)を読んでください。

# +
from azureml.core.compute import ComputeTarget, AmlCompute
from azureml.core.compute_target import ComputeTargetException

# choose a name for your cluster
cluster_name = "gpucluster"

try:
    compute_target = ComputeTarget(workspace=ws, name=cluster_name)
    print('Found existing compute target.')
except ComputeTargetException:
    print('Creating a new compute target...')
    compute_config = AmlCompute.provisioning_configuration(vm_size='STANDARD_NC6', 
                                                           max_nodes=4, vm_priority='dedicated')

    # create the cluster
    compute_target = ComputeTarget.create(ws, cluster_name, compute_config)

    compute_target.wait_for_completion(show_output=True)

# Use the 'status' property to get a detailed status for the current cluster. 
print(compute_target.status.serialize())
# -

# 上記のコードはGPUクラスターを作成します。  
# コードの中身を確認します。  
# `AmlCompute.provisioning_configuration()`でコンピューティング ターゲットの設定を行うことができます。  
# 詳細は[こちらの公式ドキュメント](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.compute.amlcompute(class)?view=azure-ml-py)を確認してください。  
#
#
# ### 仮想マシンのサイズの変更
#
# 代わりにCPUクラスタを作成したい場合は、 `STANDARD_D2_V2`のように` vm_size`パラメータに異なるVMサイズを指定してください。  
#
# CPUのVMサイズは[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/virtual-machines/linux/sizes-general)を確認してください。  
# GPUのVMサイズは[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/virtual-machines/linux/sizes-gpu)を確認してください。  
#
# 今回はNVIDIAのTesla K80が1枚の仮想マシン`STANDARD_NC6`を使用します。  
# 計算リソースを増やすためにはNCの他のシリーズを使用するもしくはGPUの枚数を増やすことによって行うことが可能です。  
#
#
# ### 仮想マシンの割り当ての設定
#
# Azureの仮想マシンのプライオリティ（優先度）を選択することができます。  
# 選択肢は`dedicated`または`lowpriority`の２つから選択することができます。  
# （デフォルトでは`dedicated`が選択されています。）  
#
# dedicatedは問題なく仮想マシンが割り当てられますが、lowpriorityは価格が安い代わりに割り込みが入る可能性などいくつかデメリットがあります。  
# しかし、価格が約8割ほど安くなるのは大きなメリットです。  
#
#
# ### クラスターのノード数の設定
#
# `max_nodes`でコンピューティングでジョブを実行中に自動スケールアップする最大ノード数を指定することが可能です。  
# ノード数はVMの数を表すため最大数が増えると計算リソースが増えますが、同時に発生する料金も増えます。  

# ## GPUクラスタを使用しての学習の実行
#
# リモートコンピューティングクラスタを使用して学習する準備が整いました。  
# Pytorchでの学習のスクリプトと学習用のデータを準備します。  
#
# 今回は事前に準備されたものを使用します。　　

# ### プロジェクトディレクトリの作成
#
# 学習実行に必要なコードを格納するディレクトリを作成します。  
# このディレクトリには学習を実行するコードと、それに依存関係のファイルなどを格納するする必要があります。  

# +
import os

project_folder = './pytorch-hymenoptera'
os.makedirs(project_folder, exist_ok=True)
# -

# 今回は`pytorch-hymenoptera`という名前のプロジェクトフォルダを作成しました。  

# ### データセットの準備
#
# 今回は[こちら](https://download.pytorch.org/tutorial/hymenoptera_data.zip)のデータセットを使用します。  
# （ダウンロードの必要はありません）
#
#
# こちらにはアリとミツバチの画像それぞれ約120個ずつの訓練データ、75個の検証データが含まれています。  
# 学習用のスクリプトである`pytorch_train.py`内にデータセットをダウンロードして取得するコードがあるため、  
# こちらのデータは今回はダウンロードして準備する必要はありません。  

# ### 学習用スクリプトの準備
#
# 学習用のスクリプトは用意されている`pytorch_train.py`を使用します。  
#
#
# ### スクリプトの確認
#
# 今回使用するスクリプトはこちらになります。  
#
# `pytorch_train.py`  
#
# ```python
#
# from __future__ import print_function, division
# import torch
# import torch.nn as nn
# import torch.optim as optim
# from torch.optim import lr_scheduler
# from torchvision import datasets, models, transforms
# import numpy as np
# import time
# import os
# import copy
# import argparse
#
# from azureml.core.run import Run
# # get the Azure ML run object
# run = Run.get_context()
#
#
# def load_data(data_dir):
#     """Load the train/val data."""
#
#     # Data augmentation and normalization for training
#     # Just normalization for validation
#     data_transforms = {
#         'train': transforms.Compose([
#             transforms.RandomResizedCrop(224),
#             transforms.RandomHorizontalFlip(),
#             transforms.ToTensor(),
#             transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
#         ]),
#         'val': transforms.Compose([
#             transforms.Resize(256),
#             transforms.CenterCrop(224),
#             transforms.ToTensor(),
#             transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
#         ]),
#     }
#
#     image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),
#                                               data_transforms[x])
#                       for x in ['train', 'val']}
#     dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,
#                                                   shuffle=True, num_workers=4)
#                    for x in ['train', 'val']}
#     dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
#     class_names = image_datasets['train'].classes
#
#     return dataloaders, dataset_sizes, class_names
#
#
# def train_model(model, criterion, optimizer, scheduler, num_epochs, data_dir):
#     """Train the model."""
#
#     # load training/validation data
#     dataloaders, dataset_sizes, class_names = load_data(data_dir)
#
#     device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
#
#     since = time.time()
#
#     best_model_wts = copy.deepcopy(model.state_dict())
#     best_acc = 0.0
#
#     for epoch in range(num_epochs):
#         print('Epoch {}/{}'.format(epoch, num_epochs - 1))
#         print('-' * 10)
#
#         # Each epoch has a training and validation phase
#         for phase in ['train', 'val']:
#             if phase == 'train':
#                 scheduler.step()
#                 model.train()  # Set model to training mode
#             else:
#                 model.eval()   # Set model to evaluate mode
#
#             running_loss = 0.0
#             running_corrects = 0
#
#             # Iterate over data.
#             for inputs, labels in dataloaders[phase]:
#                 inputs = inputs.to(device)
#                 labels = labels.to(device)
#
#                 # zero the parameter gradients
#                 optimizer.zero_grad()
#
#                 # forward
#                 # track history if only in train
#                 with torch.set_grad_enabled(phase == 'train'):
#                     outputs = model(inputs)
#                     _, preds = torch.max(outputs, 1)
#                     loss = criterion(outputs, labels)
#
#                     # backward + optimize only if in training phase
#                     if phase == 'train':
#                         loss.backward()
#                         optimizer.step()
#
#                 # statistics
#                 running_loss += loss.item() * inputs.size(0)
#                 running_corrects += torch.sum(preds == labels.data)
#
#             epoch_loss = running_loss / dataset_sizes[phase]
#             epoch_acc = running_corrects.double() / dataset_sizes[phase]
#
#             print('{} Loss: {:.4f} Acc: {:.4f}'.format(
#                 phase, epoch_loss, epoch_acc))
#
#             # deep copy the model
#             if phase == 'val' and epoch_acc > best_acc:
#                 best_acc = epoch_acc
#                 best_model_wts = copy.deepcopy(model.state_dict())
#
#             # log the best val accuracy to AML run
#             run.log('best_val_acc', np.float(best_acc))
#
#         print()
#
#     time_elapsed = time.time() - since
#     print('Training complete in {:.0f}m {:.0f}s'.format(
#         time_elapsed // 60, time_elapsed % 60))
#     print('Best val Acc: {:4f}'.format(best_acc))
#
#     # load best model weights
#     model.load_state_dict(best_model_wts)
#     return model
#
#
# def fine_tune_model(num_epochs, data_dir, learning_rate, momentum):
#     """Load a pretrained model and reset the final fully connected layer."""
#
#     # log the hyperparameter metrics to the AML run
#     run.log('lr', np.float(learning_rate))
#     run.log('momentum', np.float(momentum))
#
#     model_ft = models.resnet18(pretrained=True)
#     num_ftrs = model_ft.fc.in_features
#     model_ft.fc = nn.Linear(num_ftrs, 2)  # only 2 classes to predict
#
#     device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
#     model_ft = model_ft.to(device)
#
#     criterion = nn.CrossEntropyLoss()
#
#     # Observe that all parameters are being optimized
#     optimizer_ft = optim.SGD(model_ft.parameters(),
#                              lr=learning_rate, momentum=momentum)
#
#     # Decay LR by a factor of 0.1 every 7 epochs
#     exp_lr_scheduler = lr_scheduler.StepLR(
#         optimizer_ft, step_size=7, gamma=0.1)
#
#     model = train_model(model_ft, criterion, optimizer_ft,
#                         exp_lr_scheduler, num_epochs, data_dir)
#
#     return model
#
#
# def download_data():
#     """Download and extract the training data."""
#     import urllib
#     from zipfile import ZipFile
#     # download data
#     data_file = './hymenoptera_data.zip'
#     download_url = 'https://download.pytorch.org/tutorial/hymenoptera_data.zip'
#     urllib.request.urlretrieve(download_url, filename=data_file)
#
#     # extract files
#     with ZipFile(data_file, 'r') as zip:
#         print('extracting files...')
#         zip.extractall()
#         print('finished extracting')
#         data_dir = zip.namelist()[0]
#
#     # delete zip file
#     os.remove(data_file)
#     return data_dir
#
#
# def main():
#     print("Torch version:", torch.__version__)
#
#     # get command-line arguments
#     parser = argparse.ArgumentParser()
#     parser.add_argument('--num_epochs', type=int, default=25,
#                         help='number of epochs to train')
#     parser.add_argument('--output_dir', type=str, help='output directory')
#     parser.add_argument('--learning_rate', type=float,
#                         default=0.001, help='learning rate')
#     parser.add_argument('--momentum', type=float, default=0.9, help='momentum')
#     args = parser.parse_args()
#
#     data_dir = download_data()
#     print("data directory is: " + data_dir)
#     model = fine_tune_model(args.num_epochs, data_dir,
#                             args.learning_rate, args.momentum)
#     os.makedirs(args.output_dir, exist_ok=True)
#     torch.save(model, os.path.join(args.output_dir, 'model.pt'))
#
#
# if __name__ == "__main__":
#     main()
#
#
# ```
#
# こちらのスクリプトの詳細の説明は行いませんが、実行内容としては下記の4ステップになります。    
#
# 1. データのダウンロード
# 2. 必要な前処理の適応
# 3. 学習の実行
# 4. 結果の取得

# ### Azure MLの学習結果をログに保存
#
# 上記のコードにはAzure MLの環境で学習を実行し、結果を追跡するにはいくつかのAzure MLコードが追記されています。  
# 詳細は[こちらの公式のドキュメント](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-track-experiments)を確認してください。  
# 今回記述されている内容をそれぞれ確認しましょう。  
#
# 学習経過には`Azure ML Run`オブジェクトを使用することによってアクセスすることができます。    
# 上記のコード内で設定を行なっている部分を確認しましょう。  
#
# ```Python
# from azureml.core.run import Run
# run = Run.get_context()
# ```
#
# さらに`learning rate`、`momentum`のパラメータ、検証データに対する最高のAccuracy（正解率）のログも取得します。  
#
# ```Python
# run.log('lr', np.float(learning_rate))
# run.log('momentum', np.float(momentum))
#
# run.log('best_val_acc', np.float(best_acc))
# ```
#
# ハイパーパラメータの調整を行う際にこちらのログは重要な役割を果たします。  
# こちらのスクリプトを先ほど作成した、作業ディレクトリに保存しておきます。  

# +
import shutil

shutil.copy('pytorch_train.py', project_folder)
# -

# ### Experimentの作成
# ワークスペースですべての実行結果を追跡するために[Experiment](https://docs.microsoft.com/azure/machine-learning/service/concept-azure-machine-learning-architecture#experiment) を作成します。  

# +
from azureml.core import Experiment

experiment_name = 'pytorch-hymenoptera'
experiment = Experiment(ws, name=experiment_name)
# -

# ### PyTorch estimatorの作成
#
# Azure ML SDKのPyTorch estimatorを使用すると、単一ノードと分散の両方の実行について、PyTorchトレーニングジョブを簡単に送信できます。   
# PyTorch estimatorの詳細については、[こちら](https://docs.microsoft.com/azure/machine-learning/service/how-to-train-pytorch)を参照してください。次のコードは単一ノードのPyTorchジョブを定義します。

# +
from azureml.train.dnn import PyTorch

script_params = {
    '--num_epochs': 30,
    '--output_dir': './outputs'
}

estimator = PyTorch(source_directory=project_folder, 
                    script_params=script_params,
                    compute_target=compute_target,
                    entry_script='pytorch_train.py',
                    use_gpu=True)
# -

# `scripti_params`に訓練に必要な引数を渡す必要があります。　　
#
#
# #### script_params
#
# `script_params`は` entry_script`で指定しているスクリプトに必要な引数を渡す辞書型のオブジェクトです。  
# 今回の設定は下記になります。  
# - `--num_epochs`:`30`→エポック数を30に設定
# - `'--output_dir': './outputs'`→学習の実行履歴を保存するディレクトリの指定
#
# この出力ディレクトリである `./ output`はAzure ML上で特別に扱われます。  
# このディレクトリ内の情報は全て実行履歴の一部としてワークスペースにアップロードされ、リモート実行が終了してもアクセス可能です。
#
# #### データストアからデータの読み込み
#
# 訓練時にデータを読み込む必要がある場合はデータストアと呼ばれる場所にデータをUploadし、そこからデータを読み込む必要があります。  
# その方法については[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/machine-learning/service/how-to-access-data)を確認してください。  
# （データストアはワークスペースのリソースを作成した段階で使用可能になります。）  
#
#
# #### GPUの使用
#
# Azure VMのGPUをトレーニングに活用するには、`use_gpu = True`に設定します。

# ### ジョブの実行
#
# Estimatorオブジェクトを送信してExperimentを実行します。  
# この実行は非同期です。

run = experiment.submit(estimator)
print(run)

# to get more details of your run
print(run.get_details())

# ### 実行経過の確認
#
# Jupyter Notebookのウィジェットを使用して実行の進行状況を監視できます。  
# 実行依頼と同様に、ウィジェットは非同期で、ジョブが完了するまで10〜15秒ごとにライブアップデートを行います。  

# +
from azureml.widgets import RunDetails

RunDetails(run).show()
# -

# また、スクリプトがトレーニングを完了するまでブロックしてから、学習結果を確認することも可能です。

run.wait_for_completion(show_output=True)

# ## 学習済みモデルのデプロイ
#
# 学習済みモデルが作成できました。  
# 続いてそのモデルをAzureにデプロイします。   
# 今回はモデルを[Azure Container Instances](https://docs.microsoft.com/en-us/azure/container-instances/)（ACI）にWebサービスとしてデプロイします。   
# Azure MLを使用してモデルを展開する方法の詳細については、[こちら](https://docs.microsoft.com/azure/machine-learning/service/how-to-deploy-and-where)を参照してください。

# ### 学習済みモデルの保存
#
# `run.register_model`を使用すると学習済みモデルを保存することが可能です。  

model = run.register_model(model_name='pytorch-hymenoptera', model_path='outputs/model.pt')
print(model.name, model.id, model.version, sep = '\t')

# ### スコアリングスクリプトの作成
#
# まず、Webサービスに呼び出されるスコアリングスクリプトを作成します。  
# スコアリングスクリプトには、2つの関数が必要になります。
#
# - `init（）`：この関数では、通常モデルを `global`オブジェクトにロードします。この関数はDockerコンテナが起動されたときに一度だけ実行されます。
# - `run（input_data）`：この関数では、新たな入力データ対して学習済みモデルを使用して推論を実行します。通常は入力と出力は通常シリアライゼーションとデシリアライゼーションのフォーマットとしてJSONを使用しますが、他のフォーマットも使用することが可能です。
#
# 今回は準備されている`pytorch_score.py`を使用します。  
# また用意されているテスト用の画像ファイルを使用して推論を実行します。  
# 独自のスコアリングスクリプトを書くときは、Webサービスを実行する前にまずローカルでテストすることを忘れないでください。  
#
# 使用するスクリプトは下記になります。  
#
# ```python
#
# import torch
# import torch.nn as nn
# from torchvision import transforms
# import json
#
# from azureml.core.model import Model
#
#
# def init():
#     global model
#     model_path = Model.get_model_path('pytorch-hymenoptera')
#     model = torch.load(model_path, map_location=lambda storage, loc: storage)
#     model.eval()
#
#
# def run(input_data):
#     input_data = torch.tensor(json.loads(input_data)['data'])
#
#     # get prediction
#     with torch.no_grad():
#         output = model(input_data)
#         classes = ['ants', 'bees']
#         softmax = nn.Softmax(dim=1)
#         pred_probs = softmax(output).numpy()[0]
#         index = torch.argmax(output, 1)
#
#     result = {"label": classes[index], "probability": str(pred_probs[index])}
#     return result
#
# ```

# ### 環境ファイルを作成する
#
# スコアリングスクリプトのすべてのパッケージ依存関係を指定する環境ファイル（ `myenv.yml`）を作成する必要があります。このファイルは、Azure MLによってこれらのすべての依存関係がDockerイメージにインストールされるようにするために使用されます。この場合、 `azureml-core`、` torch`、そして `torchvision`が必要になります。

# +
from azureml.core.conda_dependencies import CondaDependencies 

myenv = CondaDependencies.create(pip_packages=['azureml-defaults', 'torch', 'torchvision'])

with open("myenv.yml","w") as f:
    f.write(myenv.serialize_to_string())
    
print(myenv.serialize_to_string())
# -

# ### Dockerイメージの設定
#
# ACIコンテナーを構築するために使用するDockerイメージを構成します。  
# 詳細については[こちらの公式ドキュメント](https://docs.microsoft.com/en-us/python/api/azureml-core/azureml.core.image.containerimage?view=azure-ml-py)を確認してください。  

# +
from azureml.core.image import ContainerImage

image_config = ContainerImage.image_configuration(execution_script='pytorch_score.py', 
                                                  runtime='python', 
                                                  conda_file='myenv.yml',
                                                  description='Image with hymenoptera model')
# -

# ### ACIコンテナの設定
#
# デプロイのための準備がほぼ整いました。   
# ACIコンテナに必要なCPUの数とギガバイトのRAMを指定するためのデプロイメント構成ファイルを作成します。  
# それは作成したモデルに依存しますが、一般的なモデルではデフォルトの `1`コアと` 1`ギガバイトのRAMで十分なケースが多いです。  

# +
from azureml.core.webservice import AciWebservice

aciconfig = AciWebservice.deploy_configuration(cpu_cores=1, 
                                               memory_gb=1, 
                                               tags={'data': 'hymenoptera',  'method':'transfer learning', 'framework':'pytorch'},
                                               description='Classify ants/bees using transfer learning with PyTorch')
# -

# ### Container Instances にデプロイする
#
# 最後に、登録したモデルからWebサービスをデプロイしましょう。  
# 前の手順で作成したACI設定ファイルとイメージ設定ファイルを使用してWebサービスをデプロイします。  
#
# リストの中の `model`オブジェクトを` models`パラメータに渡します。  
# 複数の登録済みモデルをデプロイする場合は、このリストに他のモデルを追加してください。　　

# +
# %%time
from azureml.core.webservice import Webservice

service_name = 'aci-hymenoptera'
service = Webservice.deploy_from_model(workspace=ws,
                                       name=service_name,
                                       models=[model],
                                       image_config=image_config,
                                       deployment_config=aciconfig,)

service.wait_for_deployment(show_output=True)
print(service.state)
# -

# 通常デプロイには7~8分かかります。  
# 下記のように表示されればデプロイが成功しています。  
#
# ```
# SucceededACI service creation operation finished, operation "Succeeded"
#
# ```
#
# #### デプロイがうまくいかない場合
#
# もし、何らかの理由でデプロイが失敗して再デプロイする必要がある場合は、必ずサービスを`service.delete（）`で削除してください。  
#
# **また、デプロイに問題が発生した場合、まず下記のコマンドを実行して、サービスからログを取得しましょう。**

service.get_logs()

# RESTクライアント呼び出しを受け付けるWebサービスのHTTPエンドポイントを取得します。  
# このエンドポイントは、Webサービスをテストしたい、またはそれをアプリケーションに統合したい人と共有することができます。

print(service.scoring_uri)

# ## デプロイされたサービスをテストする
#
# 最後に、デプロイしたWebサービスをテストしましょう。  
# データをJSON文字列としてACIでホストされているWebサービスに送信し、SDKの `run` APIを使用してサービスを呼び出します。  
# ここで、検証データからイメージを取得して推論を実行します。

# +
import os, json
from PIL import Image
import matplotlib.pyplot as plt

plt.imshow(Image.open('test_img.jpg'))
# -

# 画像データに対して学習時と同じ前処理を適応し、推論が実行できる状態に変更します。  

# +
import torch
from torchvision import transforms
    
def preprocess(image_file):
    """Preprocess the input image."""
    data_transforms = transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ])

    image = Image.open(image_file)
    image = data_transforms(image).float()
    image = torch.tensor(image)
    image = image.unsqueeze(0)
    return image.numpy()


# -

# デプロイしたAPIを使用して推論を実行します。  

input_data = preprocess('test_img.jpg')
result = service.run(input_data=json.dumps({'data': input_data.tolist()}))
print(result)

# うまく推論ができていることが確認できました。  
# このデプロイされたモデルに関してはAzure Portalの「デプロイ」タブから詳細情報について確認することができます。  
#
# これでAzure Machine Learningの基礎的な使用方法が理解できました。  

# ## 後片付け
#
# Webサービスが不要になったら、API呼び出しで簡単に削除できます。

service.delete()

# 続いては一緒に手持ちのデータを使用して学習を行う方法を確認します。  
# また今回は行わなかったハイパーパラメータの調整方法もご紹介します。  

StarcoderdataJupyterScriptsDedupFiltered