

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

# コンパイルに向けてモデルを準備する
<a name="neo-compilation-preparing-model"></a>

SageMaker Neo では、機械学習モデルが特定の入力データ形状を満たしている必要があります。コンパイルで求められる入力形状は、使用する深層学習フレームワークによって異なります。モデルの入力形状が正しくフォーマットされたら、以下の要件に従ってモデルを保存します。モデルを保存したら、モデルアーティファクトを圧縮します。

**Topics**
+ [SageMaker Neo が想定する入力データの形状](#neo-job-compilation-expected-inputs)
+ [SageMaker Neo 用にモデルを保存する](#neo-job-compilation-how-to-save-model)

## SageMaker Neo が想定する入力データの形状
<a name="neo-job-compilation-expected-inputs"></a>

モデルをコンパイルする前に、モデルが正しくフォーマットされていることを確認します。Neo は、トレーニング済みモデルへの想定データ入力の名前と形状が、JSON 形式またはリスト形式で渡されることを想定しています。想定入力はフレームワークによって異なります。

SageMaker Neo が想定する入力形状を以下に示します。

### Keras
<a name="collapsible-section-1"></a>

想定データ入力の名前と形状 (NCHW 形式) を指定します。トレーニング済みモデルにはディクショナリ形式を使います。Keras モデルアーティファクトは NHWC (チャネル最後) 形式でアップロードしますが、DataInputConfig は NCHW (チャネル優先) 形式で指定することに注意してください。求められるディクショナリ形式は次のとおりです。
+ 入力が 1 つの場合: `{'input_1':[1,3,224,224]}`
+ 入力が 2 つの場合: `{'input_1': [1,3,224,224], 'input_2':[1,3,224,224]}`

### MXNet/ONNX
<a name="collapsible-section-2"></a>

想定データ入力の名前と形状 (NCHW 形式) を指定します。トレーニング済みモデルにはディクショナリ形式を使います。求められるディクショナリ形式は次のとおりです。
+ 入力が 1 つの場合: `{'data':[1,3,1024,1024]}`
+ 入力が 2 つの場合: `{'var1': [1,1,28,28], 'var2':[1,1,28,28]}`

### PyTorch
<a name="collapsible-section-3"></a>

PyTorch モデルの場合、次の両方の条件を満たす場合は、使用するデータ入力の名前と形状を指定する必要はありません。
+ PyTorch 2.0 以降を使用してモデル定義ファイルを作成しました。定義ファイルの作成方法の詳細については、「Saving Models for SageMaker Neo」の「[PyTorch](#how-to-save-pytorch)」セクションを参照してください。**
+ クラウドインスタンス用にモデルをコンパイルしています。SageMaker Neo がサポートするインスタンスタイプの詳細については、「[サポートされるインスタンスタイプとフレームワーク](neo-supported-cloud.md)」を参照してください。

これらの条件を満たす場合、SageMaker Neo は PyTorch で作成したモデル定義ファイル (.pt または .pth) から入力設定を取得します。

それ以外の場合は、以下を実行する必要があります。

想定データ入力の名前と形状 (NCHW 形式) を指定します。トレーニング済みモデルにはディクショナリ形式を使います。また、リスト形式を使用して形状のみを指定することもできます。求められるディクショナリ形式は次のとおりです。
+ ディクショナリ形式で入力が 1 つの場合: `{'input0':[1,3,224,224]}`
+ リスト形式で入力が 1 つの場合: `[[1,3,224,224]]`
+ ディクショナリ形式で入力が 2 つの場合: `{'input0':[1,3,224,224], 'input1':[1,3,224,224]}`
+ リスト形式で入力が 2 つの場合: `[[1,3,224,224], [1,3,224,224]]`

### TensorFlow
<a name="collapsible-section-4"></a>

想定データ入力の名前と形状 (NHWC 形式) を指定します。トレーニング済みモデルにはディクショナリ形式を使います。求められるディクショナリ形式は次のとおりです。
+ 入力が 1 つの場合: `{'input':[1,1024,1024,3]}`
+ 入力が 2 つの場合: `{'data1': [1,28,28,1], 'data2':[1,28,28,1]}`

### TFLite
<a name="collapsible-section-5"></a>

想定データ入力の名前と形状 (NHWC 形式) を指定します。トレーニング済みモデルにはディクショナリ形式を使います。求められるディクショナリ形式は次のとおりです。
+ 入力が 1 つの場合: `{'input':[1,224,224,3]}`

**注記**  
エッジデバイスターゲットについて、SageMaker Neo は TensorFlow Lite のみをサポートしています。サポート対象の SageMaker Neo のエッジデバイスターゲットの一覧については、SageMaker Neo の「[デバイス](neo-supported-devices-edge-devices.md#neo-supported-edge-devices)」ページを参照してください。サポート対象の SageMaker Neo のクラウドインスタンスターゲットの一覧については、SageMaker Neo の「[サポートされるインスタンスタイプとフレームワーク](neo-supported-cloud.md)」ページを参照してください。

### XGBoost
<a name="collapsible-section-6"></a>

入力データの名前と形状は必要ありません。

## SageMaker Neo 用にモデルを保存する
<a name="neo-job-compilation-how-to-save-model"></a>

次のコード例は、Neo と互換性を持たせるようにモデルを保存する方法を示しています。モデルは圧縮された tar ファイル (`*.tar.gz`) としてパッケージ化されている必要があります。

### Keras
<a name="how-to-save-tf-keras"></a>

Keras モデルでは 1 つのモデル定義ファイル (`.h5`) が必要です。

Keras モデルを、SageMaker Neo と互換性を持たせるために保存するには、次の 2 つのオプションがあります。

1. `model.save("<model-name>", save_format="h5")` を使って `.h5` 形式でエクスポートする。

1. エクスポート後に `SavedModel` を Freeze する。

以下は、`tf.keras` モデルを Frozen グラフとしてエクスポートする方法 (オプション 2) の例です。

```
import os
import tensorflow as tf
from tensorflow.keras.applications.resnet50 import ResNet50
from tensorflow.keras import backend

tf.keras.backend.set_learning_phase(0)
model = tf.keras.applications.ResNet50(weights='imagenet', include_top=False, input_shape=(224, 224, 3), pooling='avg')
model.summary()

# Save as a SavedModel
export_dir = 'saved_model/'
model.save(export_dir, save_format='tf')

# Freeze saved model
input_node_names = [inp.name.split(":")[0] for inp in model.inputs]
output_node_names = [output.name.split(":")[0] for output in model.outputs]
print("Input names: ", input_node_names)
with tf.Session() as sess:
    loaded = tf.saved_model.load(sess, export_dir=export_dir, tags=["serve"]) 
    frozen_graph = tf.graph_util.convert_variables_to_constants(sess,
                                                                sess.graph.as_graph_def(),
                                                                output_node_names)
    tf.io.write_graph(graph_or_graph_def=frozen_graph, logdir=".", name="frozen_graph.pb", as_text=False)

import tarfile
tar = tarfile.open("frozen_graph.tar.gz", "w:gz")
tar.add("frozen_graph.pb")
tar.close()
```

**警告**  
`model.save(<path>, save_format='tf')` を使う `SavedModel` クラスを使ってモデルをエクスポートしないでください。この形式はトレーニングには適していますが、推論には適していません。

### MXNet
<a name="how-to-save-mxnet"></a>

MXNet モデルは 1 つのシンボルファイル `*-symbol.json` および 1 つのパラメータ `*.params files` として保存する必要があります。

------
#### [ Gluon Models ]

`HybridSequential` クラスを使ってニューラルネットワークを定義します。これにより、命令型プログラミングとは対照的な記号型プログラミングの形式でコードが実行されます。

```
from mxnet import nd, sym
from mxnet.gluon import nn

def get_net():
    net = nn.HybridSequential()  # Here we use the class HybridSequential.
    net.add(nn.Dense(256, activation='relu'),
            nn.Dense(128, activation='relu'),
            nn.Dense(2))
    net.initialize()
    return net

# Define an input to compute a forward calculation. 
x = nd.random.normal(shape=(1, 512))
net = get_net()

# During the forward calculation, the neural network will automatically infer
# the shape of the weight parameters of all the layers based on the shape of
# the input.
net(x)
                        
# hybridize model
net.hybridize()
net(x)

# export model
net.export('<model_name>') # this will create model-symbol.json and model-0000.params files

import tarfile
tar = tarfile.open("<model_name>.tar.gz", "w:gz")
for name in ["<model_name>-0000.params", "<model_name>-symbol.json"]:
    tar.add(name)
tar.close()
```

ハイブリッドモデルの詳細については、[MXNet ハイブリッド化のドキュメント](https://mxnet.apache.org/versions/1.7.0/api/python/docs/tutorials/packages/gluon/blocks/hybridize.html)を参照してください。

------
#### [ Gluon Model Zoo (GluonCV) ]

GluonCV モデルの zoo は事前にハイブリッド化されているため、それをエクスポートするだけで済みます。

```
import numpy as np
import mxnet as mx
import gluoncv as gcv
from gluoncv.utils import export_block
import tarfile

net = gcv.model_zoo.get_model('<model_name>', pretrained=True) # For example, choose <model_name> as resnet18_v1
export_block('<model_name>', net, preprocess=True, layout='HWC')

tar = tarfile.open("<model_name>.tar.gz", "w:gz")

for name in ["<model_name>-0000.params", "<model_name>-symbol.json"]:
    tar.add(name)
tar.close()
```

------
#### [ Non Gluon Models ]

ディスクに保存した場合、Gluon 以外のモデルはすべて `*-symbol` ファイルと `*.params` ファイルを使います。したがって、すでに Neo 向けの適切な形式になっています。

```
# Pass the following 3 parameters: sym, args, aux
mx.model.save_checkpoint('<model_name>',0,sym,args,aux) # this will create <model_name>-symbol.json and <model_name>-0000.params files

import tarfile
tar = tarfile.open("<model_name>.tar.gz", "w:gz")

for name in ["<model_name>-0000.params", "<model_name>-symbol.json"]:
    tar.add(name)
tar.close()
```

------

### PyTorch
<a name="how-to-save-pytorch"></a>

PyTorch モデルは入力データ型 `float32` で定義ファイル (`.pt` または `.pth`) として保存する必要があります。

モデルを保存するには、`torch.jit.trace`メソッドの後に `torch.save` メソッドを使用します。これにより、オブジェクトがディスクファイルに保存されます。デフォルトでは Python の pickle (`pickle_module=pickle`) を使って、オブジェクトと一部のメタデータを保存します。次に、保存したモデルを圧縮された tar ファイルに変換します。

```
import torchvision
import torch

model = torchvision.models.resnet18(pretrained=True)
model.eval()
inp = torch.rand(1, 3, 224, 224)
model_trace = torch.jit.trace(model, inp)

# Save your model. The following code saves it with the .pth file extension
model_trace.save('model.pth')

# Save as a compressed tar file
import tarfile
with tarfile.open('model.tar.gz', 'w:gz') as f:
    f.add('model.pth')
f.close()
```

PyTorch 2.0 以降でモデルを保存すると、SageMaker Neo は定義ファイルからモデルの入力設定 (その入力の名前と形状) を取得します。この場合、モデルをコンパイルする際に、SageMaker AI のデータ入力を設定する必要はありません。

SageMaker Neo が入力設定を取得できないようにするには、`torch.jit.trace` の `_store_inputs` パラメータを `False` に設定します。これを行うには、モデルをコンパイルするときに SageMaker AI のデータ入力を設定する必要があります。

`torch.jit.trace` メソッドの詳細については、PyTorch ドキュメントの[「TORCH.JIT.TRACE」](https://pytorch.org/docs/stable/generated/torch.jit.trace.html#torch.jit.trace)を参照してください。

### TensorFlow
<a name="how-to-save-tf"></a>

TensorFlow では 1 つの `.pb` ファイルまたは 1 つの `.pbtxt` ファイルと変数を含む変数ディレクトリが必要です。Frozen モデルの場合、必要なのは `.pb` ファイルまたは `.pbtxt` ファイルのいずれか 1 つのみです。

次のコード例は、Linux の tar コマンドを使ってモデルを圧縮する方法を示しています。ターミナルまたは Jupyter ノートブック (Jupyter ノートブックを使っている場合は、ステートメントの冒頭に `!` マジックコマンドを挿入します) で以下を実行します:

```
# Download SSD_Mobilenet trained model
!wget http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v2_coco_2018_03_29.tar.gz

# unzip the compressed tar file
!tar xvf ssd_mobilenet_v2_coco_2018_03_29.tar.gz

# Compress the tar file and save it in a directory called 'model.tar.gz'
!tar czvf model.tar.gz ssd_mobilenet_v2_coco_2018_03_29/frozen_inference_graph.pb
```

この例で使われているコマンドフラグは、次を実行します。
+ `c`: アーカイブを作成する
+ `z`: gzip を使ってアーカイブを圧縮する
+ `v`: アーカイブの進行状況を表示する
+ `f`: アーカイブのファイル名を指定する。

### 組み込み推定器
<a name="how-to-save-built-in"></a>

組み込み推定器は、フレームワーク固有のコンテナ、またはアルゴリズム固有のコンテナのいずれかによって作成されます。組み込みのアルゴリズム固有およびフレームワーク固有の推定器の推定器オブジェクトは、いずれも組み込みの `.fit` メソッドを使ってモデルをトレーニングするときに、モデルを正しい形式で保存します。

例えば、`sagemaker.TensorFlow` を使って TensorFlow 推定器を定義できます。

```
from sagemaker.train import ModelTrainer
from sagemaker.train.configs import Compute, SourceCode

model_trainer = ModelTrainer(
    training_image='insert appropriate TensorFlow training image URI',
    role=role,  #param role can be arn of a sagemaker execution role
    compute=Compute(instance_type='ml.c4.xlarge', instance_count=2),
    hyperparameters={
        'training_steps': '1000',
        'evaluation_steps': '100',
    },
    source_code=SourceCode(entry_script='mnist.py'),
)
```

次に、 `.train`メソッドを使用してモデルをトレーニングします。

```
model_trainer.train(inputs)
```

最後に組み込みの `compile_model` メソッドを使ってモデルをコンパイルする前に:

```
# Neo compilation in V3 uses ModelBuilder.optimize() with compilation_config
from sagemaker.serve import ModelBuilder

# Specify output path of the compiled model
output_path = '/'.join(model_trainer.output_path.split('/')[:-1])

model_builder = ModelBuilder(
    model=model_trainer,
    role_arn=role,
    instance_type='ml.c5.xlarge',
)
optimized_model = model_builder.optimize(
    instance_type='ml.c5.xlarge',
    output_path=output_path,
    compilation_config={
        'OverrideEnvironment': {
            'OPTION_TARGET_INSTANCE_FAMILY': 'ml_c5',
            'OPTION_FRAMEWORK': 'tensorflow',
            'OPTION_FRAMEWORK_VERSION': '1.15.3',
        },
    },
)
```

SageMaker Python SDK から、`sagemaker.estimator.Estimator` クラスを使って推定器オブジェクトを初期化し、組み込みアルゴリズムのトレーニングと `compile_model` メソッド を使ったコンパイルを行うこともできます。

```
from sagemaker.core import image_uris
from sagemaker.core.helper.session_helper import Session
from sagemaker.train import ModelTrainer
from sagemaker.train.configs import Compute, InputData

sagemaker_session = Session()
aws_region = sagemaker_session.boto_region_name

# Specify built-in algorithm training image
training_image = image_uris.retrieve(framework='image-classification', 
                          region=aws_region, image_scope='training')

# Create ModelTrainer object for training
model_trainer = ModelTrainer(training_image=training_image,
                                          role=role,  #param role can be arn of a sagemaker execution role
                                          compute=Compute(
                                              instance_count=1,
                                              instance_type='ml.p3.8xlarge',
                                              volume_size_in_gb=50,
                                          ),
                                          output_data_config={'s3_output_path': s3_training_output_location},
                                          base_job_name='image-classification-training'
                                          )
                                          
# Setup the input data_channels to be used later for training.                                          
train_data = InputData(channel_name='train', data_source=s3_training_data_location)
validation_data = InputData(channel_name='validation', data_source=s3_validation_data_location)
data_channels = [train_data, validation_data]

# Train model
model_trainer.train(inputs=data_channels)

# Neo compilation in V3 uses ModelBuilder.optimize() with compilation_config
from sagemaker.serve import ModelBuilder

model_builder = ModelBuilder(
    model=model_trainer,
    role_arn=role,
    instance_type='ml.c5.xlarge',
)
optimized_model = model_builder.optimize(
    instance_type='ml.c5.xlarge',
    output_path=s3_compilation_output_location,
    compilation_config={
        'OverrideEnvironment': {
            'OPTION_TARGET_INSTANCE_FAMILY': 'ml_c5',
            'OPTION_FRAMEWORK': 'mxnet',
            'OPTION_FRAMEWORK_VERSION': '1.7',
        },
    },
)
```

SageMaker Python SDK を使ってモデルをコンパイルする方法の詳細については、「[モデルをコンパイルする (Amazon SageMaker AI SDK)](neo-job-compilation-sagemaker-sdk.md)」を参照してください。