

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# 前提条件
<a name="neo-deployment-hosting-services-prerequisites"></a>

**注記**  
 AWS SDK for Python (Boto3)、、または SageMaker AI コンソールを使用してモデルをコンパイルした場合は AWS CLI、このセクションの手順に従います。

SageMaker Neo コンパイルのモデルを作成するには、次が必要です。

1. Docker イメージの Amazon ECR URI。[こちらのリスト](https://docs.aws.amazon.com/sagemaker/latest/dg/neo-deployment-hosting-services-container-images.html)から、ニーズに合ったものを選択できます。

1. エントリポイントスクリプトファイル

   1. **PyTorch モデルと MXNet モデルの場合**

      SageMaker AI を使ってモデルをトレーニングした場合、トレーニングスクリプトには以下に説明する関数を実装する必要があります。**トレーニングスクリプトは推論時にエントリポイントスクリプトとして機能します。「[MXNet モジュールと SageMaker Neo を使って MNIST をトレーニング、コンパイル、デプロイする](https://sagemaker-examples.readthedocs.io/en/latest/sagemaker_neo_compilation_jobs/mxnet_mnist/mxnet_mnist_neo.html)」で詳しく説明されている例では、トレーニングスクリプト (`mnist.py`) には、必要な関数が実装されています。

      SageMaker AI を使ってモデルをトレーニングしなかった場合は、推論時に使えるエントリポイントスクリプト (`inference.py`) ファイルを提供する必要があります。**フレームワーク (MXNet または PyTorch) に基づいて、推論スクリプトの場所は SageMaker Python SDK の [MXNet のモデルディレクトリ構造](https://sagemaker.readthedocs.io/en/stable/frameworks/mxnet/using_mxnet.html#model-directory-structure)または [PyTorch のモデルディレクトリ構造](https://sagemaker.readthedocs.io/en/stable/frameworks/pytorch/using_pytorch.html#model-directory-structure)に従う必要があります。

      **PyTorch** と**MXNet** を使って Neo 推論最適化コンテナイメージを CPU および GPU インスタンスタイプで使う場合、推論スクリプトには次の関数を実装する必要があります。
      + `model_fn`: モデルをロードします。(オプション)
      + `input_fn`: 受信リクエストペイロードを numpy 配列に変換します。
      + `predict_fn`: 予測を実行します。
      + `output_fn`: 予測出力をレスポンスペイロードに変換します。
      + または、`transform_fn` を定義して、`input_fn`、`predict_fn`、`output_fn` を結合します。

      以下は、**PyTorch と MXNet (Gluon および Module)** の場合の、ディレクトリ `code` 内の `inference.py` スクリプト (`code/inference.py`) の例です。これらの例では、まずモデルをロードし、GPU でイメージデータを処理します。

------
#### [ MXNet Module ]

      ```
      import numpy as np
      import json
      import mxnet as mx
      import neomx  # noqa: F401
      from collections import namedtuple
      
      Batch = namedtuple('Batch', ['data'])
      
      # Change the context to mx.cpu() if deploying to a CPU endpoint
      ctx = mx.gpu()
      
      def model_fn(model_dir):
          # The compiled model artifacts are saved with the prefix 'compiled'
          sym, arg_params, aux_params = mx.model.load_checkpoint('compiled', 0)
          mod = mx.mod.Module(symbol=sym, context=ctx, label_names=None)
          exe = mod.bind(for_training=False,
                         data_shapes=[('data', (1,3,224,224))],
                         label_shapes=mod._label_shapes)
          mod.set_params(arg_params, aux_params, allow_missing=True)
          
          # Run warm-up inference on empty data during model load (required for GPU)
          data = mx.nd.empty((1,3,224,224), ctx=ctx)
          mod.forward(Batch([data]))
          return mod
      
      
      def transform_fn(mod, image, input_content_type, output_content_type):
          # pre-processing
          decoded = mx.image.imdecode(image)
          resized = mx.image.resize_short(decoded, 224)
          cropped, crop_info = mx.image.center_crop(resized, (224, 224))
          normalized = mx.image.color_normalize(cropped.astype(np.float32) / 255,
                                        mean=mx.nd.array([0.485, 0.456, 0.406]),
                                        std=mx.nd.array([0.229, 0.224, 0.225]))
          transposed = normalized.transpose((2, 0, 1))
          batchified = transposed.expand_dims(axis=0)
          casted = batchified.astype(dtype='float32')
          processed_input = casted.as_in_context(ctx)
      
          # prediction/inference
          mod.forward(Batch([processed_input]))
      
          # post-processing
          prob = mod.get_outputs()[0].asnumpy().tolist()
          prob_json = json.dumps(prob)
          return prob_json, output_content_type
      ```

------
#### [ MXNet Gluon ]

      ```
      import numpy as np
      import json
      import mxnet as mx
      import neomx  # noqa: F401
      
      # Change the context to mx.cpu() if deploying to a CPU endpoint
      ctx = mx.gpu()
      
      def model_fn(model_dir):
          # The compiled model artifacts are saved with the prefix 'compiled'
          block = mx.gluon.nn.SymbolBlock.imports('compiled-symbol.json',['data'],'compiled-0000.params', ctx=ctx)
          
          # Hybridize the model & pass required options for Neo: static_alloc=True & static_shape=True
          block.hybridize(static_alloc=True, static_shape=True)
          
          # Run warm-up inference on empty data during model load (required for GPU)
          data = mx.nd.empty((1,3,224,224), ctx=ctx)
          warm_up = block(data)
          return block
      
      
      def input_fn(image, input_content_type):
          # pre-processing
          decoded = mx.image.imdecode(image)
          resized = mx.image.resize_short(decoded, 224)
          cropped, crop_info = mx.image.center_crop(resized, (224, 224))
          normalized = mx.image.color_normalize(cropped.astype(np.float32) / 255,
                                        mean=mx.nd.array([0.485, 0.456, 0.406]),
                                        std=mx.nd.array([0.229, 0.224, 0.225]))
          transposed = normalized.transpose((2, 0, 1))
          batchified = transposed.expand_dims(axis=0)
          casted = batchified.astype(dtype='float32')
          processed_input = casted.as_in_context(ctx)
          return processed_input
      
      
      def predict_fn(processed_input_data, block):
          # prediction/inference
          prediction = block(processed_input_data)
          return prediction
      
      def output_fn(prediction, output_content_type):
          # post-processing
          prob = prediction.asnumpy().tolist()
          prob_json = json.dumps(prob)
          return prob_json, output_content_type
      ```

------
#### [ PyTorch 1.4 and Older ]

      ```
      import os
      import torch
      import torch.nn.parallel
      import torch.optim
      import torch.utils.data
      import torch.utils.data.distributed
      import torchvision.transforms as transforms
      from PIL import Image
      import io
      import json
      import pickle
      
      
      def model_fn(model_dir):
          """Load the model and return it.
          Providing this function is optional.
          There is a default model_fn available which will load the model
          compiled using SageMaker Neo. You can override it here.
      
          Keyword arguments:
          model_dir -- the directory path where the model artifacts are present
          """
      
          # The compiled model is saved as "compiled.pt"
          model_path = os.path.join(model_dir, 'compiled.pt')
          with torch.neo.config(model_dir=model_dir, neo_runtime=True):
              model = torch.jit.load(model_path)
              device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
              model = model.to(device)
      
          # We recommend that you run warm-up inference during model load
          sample_input_path = os.path.join(model_dir, 'sample_input.pkl')
          with open(sample_input_path, 'rb') as input_file:
              model_input = pickle.load(input_file)
          if torch.is_tensor(model_input):
              model_input = model_input.to(device)
              model(model_input)
          elif isinstance(model_input, tuple):
              model_input = (inp.to(device) for inp in model_input if torch.is_tensor(inp))
              model(*model_input)
          else:
              print("Only supports a torch tensor or a tuple of torch tensors")
              return model
      
      
      def transform_fn(model, request_body, request_content_type,
                       response_content_type):
          """Run prediction and return the output.
          The function
          1. Pre-processes the input request
          2. Runs prediction
          3. Post-processes the prediction output.
          """
          # preprocess
          decoded = Image.open(io.BytesIO(request_body))
          preprocess = transforms.Compose([
              transforms.Resize(256),
              transforms.CenterCrop(224),
              transforms.ToTensor(),
              transforms.Normalize(
                  mean=[
                      0.485, 0.456, 0.406], std=[
                      0.229, 0.224, 0.225]),
          ])
          normalized = preprocess(decoded)
          batchified = normalized.unsqueeze(0)
          # predict
          device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
          batchified = batchified.to(device)
          output = model.forward(batchified)
      
          return json.dumps(output.cpu().numpy().tolist()), response_content_type
      ```

------
#### [ PyTorch 1.5 and Newer ]

      ```
      import os
      import torch
      import torch.nn.parallel
      import torch.optim
      import torch.utils.data
      import torch.utils.data.distributed
      import torchvision.transforms as transforms
      from PIL import Image
      import io
      import json
      import pickle
      
      
      def model_fn(model_dir):
          """Load the model and return it.
          Providing this function is optional.
          There is a default_model_fn available, which will load the model
          compiled using SageMaker Neo. You can override the default here.
          The model_fn only needs to be defined if your model needs extra
          steps to load, and can otherwise be left undefined.
      
          Keyword arguments:
          model_dir -- the directory path where the model artifacts are present
          """
      
          # The compiled model is saved as "model.pt"
          model_path = os.path.join(model_dir, 'model.pt')
          device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
          model = torch.jit.load(model_path, map_location=device)
          model = model.to(device)
      
          return model
      
      
      def transform_fn(model, request_body, request_content_type,
                          response_content_type):
          """Run prediction and return the output.
          The function
          1. Pre-processes the input request
          2. Runs prediction
          3. Post-processes the prediction output.
          """
          # preprocess
          decoded = Image.open(io.BytesIO(request_body))
          preprocess = transforms.Compose([
                                      transforms.Resize(256),
                                      transforms.CenterCrop(224),
                                      transforms.ToTensor(),
                                      transforms.Normalize(
                                          mean=[
                                              0.485, 0.456, 0.406], std=[
                                              0.229, 0.224, 0.225]),
                                          ])
          normalized = preprocess(decoded)
          batchified = normalized.unsqueeze(0)
          
          # predict
          device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
          batchified = batchified.to(device)
          output = model.forward(batchified)
          return json.dumps(output.cpu().numpy().tolist()), response_content_type
      ```

------

   1.  **inf1 インスタンスまたは ONNX、XGBoost、Keras のコンテナイメージの場合** 

      その他のすべての Neo 推論最適化コンテナイメージ、または Inferentia インスタンスタイプの場合、エントリポイントスクリプトには次の Neo Deep Learning Runtime 用の関数を実装する必要があります。
      + `neo_preprocess`: 受信リクエストペイロードを numpy 配列に変換します。
      + `neo_postprocess`: Neo Deep Learning Runtime の予測出力をレスポンス本体に変換します。
**注記**  
これら 2 つの機能は MXNet、PyTorch、TensorFlow の関数をどれも使いません。

      これらの関数の使用例については、「[Neo モデルコンパイルサンプルノートブック](https://docs.aws.amazon.com//sagemaker/latest/dg/neo.html#neo-sample-notebooks)」を参照してください。

   1. **TensorFlow モデルの場合**

      モデルにデータを送信する前にモデルに前処理および後処理のカスタムロジックが必要である場合は、推論時に使えるエントリポイントスクリプト (`inference.py`) ファイルを指定する必要があります。スクリプトには `input_handler` 関数と `output_handler` 関数のペア、または単一のハンドラ関数のどちらかを実装します。
**注記**  
ハンドラ関数が実装されている場合、`input_handler` と `output_handler` は無視されます。

      以下の `inference.py` スクリプトのコード例は、コンパイルモデルと合わせて、イメージ分類モデルに対するカスタムの前処理および後処理を実行するものです。SageMaker AI クライアントは、`application/x-image` コンテンツタイプとしてイメージファイルを `input_handler` 関数に送信します。この関数はイメージファイルを JSON に変換します。変換されたイメージファイルは、REST API を使って [TensorFlow モデルサーバー (TFX)](https://www.tensorflow.org/tfx/serving/api_rest) に送信されます。

      ```
      import json
      import numpy as np
      import json
      import io
      from PIL import Image
      
      def input_handler(data, context):
          """ Pre-process request input before it is sent to TensorFlow Serving REST API
          
          Args:
          data (obj): the request data, in format of dict or string
          context (Context): an object containing request and configuration details
          
          Returns:
          (dict): a JSON-serializable dict that contains request body and headers
          """
          f = data.read()
          f = io.BytesIO(f)
          image = Image.open(f).convert('RGB')
          batch_size = 1
          image = np.asarray(image.resize((512, 512)))
          image = np.concatenate([image[np.newaxis, :, :]] * batch_size)
          body = json.dumps({"signature_name": "serving_default", "instances": image.tolist()})
          return body
      
      def output_handler(data, context):
          """Post-process TensorFlow Serving output before it is returned to the client.
          
          Args:
          data (obj): the TensorFlow serving response
          context (Context): an object containing request and configuration details
          
          Returns:
          (bytes, string): data to return to client, response content type
          """
          if data.status_code != 200:
              raise ValueError(data.content.decode('utf-8'))
      
          response_content_type = context.accept_header
          prediction = data.content
          return prediction, response_content_type
      ```

      カスタムの前処理または後処理がない場合、SageMaker AI クライアントはファイルイメージを SageMaker AI エンドポイントに送信する前に、類似の方法で JSON に変換します。

      詳細については、「[SageMaker Python SDK で TensorFlow サービングエンドポイントにデプロイする](https://sagemaker.readthedocs.io/en/stable/frameworks/tensorflow/deploying_tensorflow_serving.html#providing-python-scripts-for-pre-pos-processing)」を参照してください。

1. コンパイル済みモデルのアーティファクトを含む Amazon S3 バケットの URI。