ResNet50は、広く使用されている古典的な構造ネットワークです。 ResNet50モデルを最適化することは、さまざまなモデル展開および推論シナリオで大きな実用的価値をもたらします。 このトピックでは、Platform for AI (PAI)-Bladeを使用してTensorFlow ResNet50モデルを最適化する方法について説明します。
背景情報
残差ニューラルネットワーク (ResNet) は、画像分野における深層学習モデルの「Hello World」プラクティスとして機能します。 ResNetモデルは、オブジェクト分類において広く使用されている。 さらに、ResNetモデルは、コンピュータビジョン用の従来のニューラルネットワークの一部であり、画像から畳み込み特徴を抽出するために使用できます。 典型的なResNetネットワークは、ResNet26、ResNet50、およびResNet101を含む。
制限事項
このトピックの手順で使用する環境は、次のバージョン要件を満たす必要があります。
システム環境: LinuxでのPython 3.6以降とCompute Unified Device Architecture (CUDA) 10.0
フレームワーク: TensorFlow 1.15
推論最適化ツール: PAI-Blade V3.17.0以降
手順
PAI-Bladeを使用してTensorFlow ResNet50モデルを最適化するには、次の手順を実行します。
TensorRT最適化をサポートするPAI-Bladeのホイールパッケージをインストールし、ResNet50モデルとテストデータをダウンロードします。
モデルを最適化するには、
blade.optimize
メソッドを呼び出します。元のモデルと最適化されたモデルの推論速度をテストして、最適化レポートの情報を確認します。
PAI-Blade SDKを統合して、推論用に最適化されたモデルをロードします。
ステップ1: 準備をする
この例では、ResNet50モデルで有効になる主な最適化項目はTensorRTです。 したがって、TensorRT最適化をサポートするPAI-Blade V3.17.0以降をインストールする必要があります。
TensorFlow 1.15.0およびCUDA 10.0に対応するPAI-Bladeをインストールします。
pip3 install pai_blade_gpu==3.17.0 -f https://pai-blade.oss-cn-zhangjiakou.aliyuncs.com/release/repo.html
TensorFlow ResNet50モデルと対応するテストデータをダウンロードします。
wget http://pai-blade.cn-hangzhou.oss.aliyun-inc.com/tutorials/tf_resnet50_v1.5.tar.gz
ダウンロードしたtf_resnet50_v1.5.tar.gzパッケージは、ResNet50モデルであるfrozen.pbファイルと、さまざまなバッチサイズの対応するテストデータで構成されています。 パッケージを手動で解凍する必要があります。
tar zxvf tf_resnet50_v1.5.tar.gz
ステップ2: PAI-Bladeを使用してモデルを最適化する
前の手順でダウンロードしたTARパッケージからTensorFlowモデルとテストデータを取得します。
import os os.environ["CUDA_VISIBLE_DEVICES"] = "1" import numpy as np import time # import tf to import graphdef model. import tensorflow.compat.v1 as tf import blade from blade.model.tf_model import TfModel def _load_model_and_data(): local_dir = "./tf_resnet50_v1.5/" model_path = os.path.abspath(os.path.join(local_dir, "frozen.pb")) data_path = os.path.abspath(os.path.join(local_dir, "test_bc1.npy")) graph_def = tf.GraphDef() with open(model_path, 'rb') as f: graph_def.ParseFromString(f.read()) test_data = np.load(data_path, allow_pickle=True, encoding='bytes').item() return graph_def, test_data # Let's go! # Load resnet model and test data. graph_def, test_data = _load_model_and_data() print(test_data)
PAI − Bladeを使用してTensorRT最適化を行う。
TensorRT最適化は、入力のタイプに基づいて、次の2つのモードのいずれかで実行できます。
静的形状の最適化
このモードは、入力がモデル推論要求において同じ形状である場合に適用可能である。 例えば、特定のサイズの入力のみがレイテンシを低減することができる。 次のサンプルコードに例を示します。
config = blade.Config() config.gpu_config.aicompiler.enable = False config.gpu_config.disable_fp16_accuracy_check = True config.gpu_config.tensorrt.enable = True # TensorRT optimization is enabled by default, you can also use this param to disable if necessary. # Function `optimize` is the entrance to Blade's one-stop optimization. optimized_model_static, opt_spec_static, report = blade.optimize( graph_def, # The original model, here is a TF GraphDef. 'o1', # Optimization level o1 or o2. device_type='gpu', # Target device to run the optimized model. config=config, # The blade.Config with more detailed optimizations configs outputs=['softmax_tensor'], # Name of outputs nodes. You can provide them or blade will guess. test_data=[test_data] ) print(report)
次のような最適化レポートが表示されます。
{ "software_context": [ { "software": "tensorflow", "version": "1.15.0" }, { "software": "cuda", "version": "10.0.0" } ], "hardware_context": { "device_type": "gpu", "microarchitecture": "T4" }, "user_config": "", "diagnosis": { "model": "tmp_graph.pbtxt", "test_data_source": "user provided", "shape_variation": "dynamic", "message": "", "test_data_info": "input_tensor:0 shape: (1, 224, 224, 3) data type: float32" }, "optimizations": [ { "name": "Tf2TrtPlus", "status": "effective", "speedup": "3.37", "pre_run": "6.81 ms", "post_run": "2.02 ms" }, { "name": "TfStripUnusedNodes", "status": "effective", "speedup": "na", "pre_run": "na", "post_run": "na" }, { "name": "TfFoldConstants", "status": "effective", "speedup": "na", "pre_run": "na", "post_run": "na" } ], "overall": { "baseline": "6.98 ms", "optimized": "2.11 ms", "speedup": "3.31" }, "model_info": { "input_format": "frozen_pb" }, "compatibility_list": [ { "device_type": "gpu", "microarchitecture": "T4" } ], "model_sdk": {} }
最適化のために余分なパラメータは設定されない。 したがって、静的形状最適化が可能になり、
test_data
の形状が使用される。 上記の最適化レポートは、Tf2TrtPlus
最適化項目が有効になることを示しています。 この場合、入力の形状が最適化のために指定された形状と一致しない場合、元のTensorFlow画像に対してモデル推論が実行されます。 推論の効率は大きく低下する。上記の最適化レポートは参考用です。 モデルの実際の最適化効果が優先されます。 最適化レポートのパラメーターの詳細については、「最適化レポート」をご参照ください。
ダイナミック形状最適化
デプロイするPAI-Bladeがバッチ処理機能をサポートしている場合、サーバーは特定の期間内に受信したリクエストをバッチにパッケージ化します。 バッチのサイズは、短期間にサーバーが受信したリクエストの数によって異なります。 したがって、バッチサイズが変わる可能性があります。 このような動的形状の最適化をサポートするために、PAI − BladeはTensorRTを統合することによって動的形状最適化をサポートする。 動的形状最適化を有効にするには、TensorRTConfigクラスのみを設定する必要があります。 次のサンプルコードに例を示します。 TensorRTConfigクラスの設定方法の詳細については、このトピックの「付録: TensorRTConfig」をご参照ください。
config_dynamic = blade.Config() config_dynamic.gpu_config.aicompiler.enable = False config_dynamic.gpu_config.disable_fp16_accuracy_check = True config_dynamic.gpu_config.tensorrt.enable = True config_dynamic.gpu_config.tensorrt.dynamic_tuning_shapes = { "min": [1, 224, 224, 3], "opts": [ [1, 224, 224, 3], [2, 224, 224, 3], [4, 224, 224, 3], [8, 224, 224, 3], ], "max": [8, 224, 224, 3], } # Call Blade's one-stop optimization, with a dynamic shapes setting for TensorRT optimization. optimized_model_dynamic, opt_spec_dynamic, report = blade.optimize( graph_def, 'o1', device_type='gpu', config=config_dynamic, outputs=['softmax_tensor'], test_data=[test_data] ) print(report) with tf.gfile.FastGFile('optimized_model_dynamic.pb', mode='wb') as f: f.write(optimized_model_dynamic.SerializeToString())
次のような最適化レポートが表示されます。
{ "software_context": [ { "software": "tensorflow", "version": "1.15.0" }, { "software": "cuda", "version": "10.0.0" } ], "hardware_context": { "device_type": "gpu", "microarchitecture": "T4" }, "user_config": "", "diagnosis": { "model": "tmp_graph.pbtxt", "test_data_source": "user provided", "shape_variation": "dynamic", "message": "", "test_data_info": "input_tensor:0 shape: (1, 224, 224, 3) data type: float32" }, "optimizations": [ { "name": "Tf2TrtPlus", "status": "effective", "speedup": "3.96", "pre_run": "7.98 ms", "post_run": "2.02 ms" }, { "name": "TfStripUnusedNodes", "status": "effective", "speedup": "na", "pre_run": "na", "post_run": "na" }, { "name": "TfFoldConstants", "status": "effective", "speedup": "na", "pre_run": "na", "post_run": "na" } ], "overall": { "baseline": "7.87 ms", "optimized": "2.52 ms", "speedup": "3.12" }, "model_info": { "input_format": "frozen_pb" }, "compatibility_list": [ { "device_type": "gpu", "microarchitecture": "T4" } ], "model_sdk": {} }
前述の最適化レポートは、静的形状最適化で表示されるレポートと同様です。 推論が実行される入力の形状が、
min
およびmax
パラメーターの値によって定義される範囲に属する場合、TensorRT最適化が使用されることに注意してください。 それ以外の場合、推論は元のTensorFlowイメージに対して実行されます。上記の最適化レポートは参考用です。 モデルの実際の最適化効果が優先されます。 最適化レポートのパラメーターの詳細については、「最適化レポート」をご参照ください。
ステップ3: パフォーマンスを確認する
最適化が完了したら、次のPythonスクリプトを実行して、最適化レポートの情報を確認できます。
import time
with tf.Session(config=TfModel.new_session_config()) as sess, opt_spec_dynamic:
sess.graph.as_default()
tf.import_graph_def(optimized_model_dynamic, name="")
# Warmup!
for i in range(0, 100):
sess.run(['softmax_tensor:0'], test_data)
# Benchmark!
num_runs = 1000
start = time.time()
for i in range(0, num_runs):
sess.run(['softmax_tensor:0'], test_data)
elapsed = time.time() - start
rt_ms = elapsed / num_runs * 1000.0
# Show the result!
print("Latency of optimized model: {:.2f}".format(rt_ms))
次のような情報が表示されます。
Latency of optimized model: 2.26
上記の出力では、最適化モデルの推論レイテンシは2.26 msです。 この値は基本的に、最適化レポートの全体的なパラメータの中で2.52ミリ秒
である最適化されたパラメータの値と一致しています。 テストデータの形状は、動的形状最適化のために指定された範囲に属するため、最適化が有効になる。 上記の最適化レポートは参考用です。 モデルの実際の最適化効果が優先されます。
ステップ4: 最適化されたモデルをロードして実行する
検証が完了したら、最適化されたモデルをデプロイできます。 PAI-Bladeは、統合できるPython用のSDKとC ++ 用のSDKを提供しています。 SDK For C ++ の使用方法の詳細については、「SDKを使用して推論用のTensorFlowモデルをデプロイする」をご参照ください。 次のセクションでは、SDK for Pythonを使用してモデルをデプロイする方法について説明します。
オプション: 試用期間中に、次の環境変数設定を追加して、認証の失敗によるプログラムの予期しない停止を防止します。
export BLADE_AUTH_USE_COUNTING=1
PAI-Bladeを使用するように認証されます。
export BLADE_REGION=<region> export BLADE_TOKEN=<token>
ビジネス要件に基づいて、次のパラメーターを設定します。
<region>: PAI-Bladeを使用するリージョンです。 PAI-BladeユーザーのDingTalkグループに参加して、PAI-Bladeを使用できるリージョンを取得できます。 DingTalkグループのQRコードについては、「アクセストークンの取得」をご参照ください。
<token>: PAI-Bladeを使用するために必要な認証トークン。 PAI-BladeユーザーのDingTalkグループに参加して、認証トークンを取得できます。 DingTalkグループのQRコードについては、「アクセストークンの取得」をご参照ください。
最適化されたモデルをロードして実行します。
import blade.ru ntime.tensorflow
を推論コードに追加します。 これに加えて、PAI-Blade SDKを統合するための追加のコードを記述したり、元の推論コードを変更したりする必要はありません。 次の例では、動的形状に対してTensorRTを使用して最適化されたモデルを使用します。import tensorflow.compat.v1 as tf import blade.runtime.tensorflow infer_data = np.load('./tf_resnet50_v1.5/test_bc1.npy', allow_pickle=True, encoding='bytes').item() # optimized model produced by blade.optimize model_path = './optimized_model_dynamic.pb' graph_def = tf.GraphDef() with open(model_path, 'rb') as f: graph_def.ParseFromString(f.read()) with tf.Session() as sess: sess.graph.as_default() tf.import_graph_def(graph_def, name="") print(sess.run(['softmax_tensor:0'], infer_data))
付録: TensorRTConfig
TensorRT最適化の特殊な性質により、PAI-Bladeは、さまざまな展開要件を満たすために使用できるクラスを提供します。
class TensorRTConfig():
def __init__(self) -> None:
self.enable = True
self.dynamic_tuning_shapes: Dict[str, List[List[Any]]] = dict()
......
TensorRTConfigクラスには、次の主要なパラメーターが含まれます。
enable
: TensorRT最適化を有効にするかどうかを指定します。 このパラメーターの値はブール値です。 GPUデバイスで最適化を実行すると、デフォルトでTensorRT最適化が有効になります。dynamic_tuning_shapes
: 最適化のための形状のディクショナリ。 サーバによって受信される要求は、異なるサイズの入力を含み得る。 これらの入力に基づいて最適化を実行するために、PAI − Bladeは動的形状最適化をサポートする。 最適化の形状のディクショナリを定義するには、このパラメーターを設定する必要があります。dynamic_tuning_shapes
パラメーターには、min
、max
、opts
の3つのキーが含まれます。min
キーとmax
キーは、入力できる最小サイズと最大サイズを指定します。 キーの値の型はList[List[int]]
です。opts
キーは、複数のサイズの入力を指定します。 キーの値の型はList[List[List[int]]]
です。説明opts
キーで指定されたサイズは、最小サイズと最大サイズで定義された範囲に属している必要があります。 それ以外の場合、\'opts\'のDim値はmin_dimとmax_dimの間にありません
エラーはTensorRT最適化のために報告されます。次のサンプルコードは、dynamic_tuning_shapesパラメーターの設定方法の例を示しています。 この例では、
opts
キーで指定されたサイズは、最小サイズよりも大きく、最大サイズよりも小さくなっています。{ "min": [[1, 3, 224, 224], [1, 50]], # lower bound of the dynamic range of each inputs. "opts": [ [[1, 3, 512, 512], [1, 60]], [[1, 3, 320, 320], [1, 55]], ], # shapes that should be optimized like static shapes "max": [[1, 3, 1024, 1024], [1, 70]] # upper bound of the dynamic range. }