TVMはモデルを高速化し、推論を最適化します

TVMはモデルを高速化し、推論を最適化します

TVM は、あらゆる種類の CPU、GPU、その他の特殊なアクセラレータで動作するオープンソースのディープラーニング コンパイラです。その目標は、あらゆるハードウェア上でモデルを最適化して実行できるようにすることです。モデルの生産性に重点を置くディープラーニング フレームワークとは異なり、TVM はハードウェア上のモデルのパフォーマンスと効率に重点を置いています。

この記事では、TVM のコンパイル プロセスと、独自のモデルを自動的に調整する方法について簡単に説明します。さらに詳しい情報については、TVM公式コンテンツを参照してください。

  • 書類:   ​​https://tvm.apache.org/docs/​​
  • ソースコード:   ​​https://github.com/apache/tvm​​

コンパイルプロセス

TVM ドキュメント デザインと建築 サンプルのコンパイル プロセス、論理構造コンポーネント、デバイス ターゲットの実装などについて説明します。プロセスを次の図に示します。

大まかに言えば、必要な手順は次のとおりです。

  • インポート: フロントエンド コンポーネントは、モデルの内部表現 (IR) の関数のコレクションである IRModule にモデルを抽出します。
  • 変換: コンパイラは、IRModule を機能的に同等またはほぼ同等の別の IRModule (量子化の場合など) に変換します。ほとんどの変換はターゲット (バックエンド) に依存しません。 TVM では、ターゲットがコンバージョン チャネルの構成に影響を与えることもできます。
  • ターゲット変換: コンパイラは IRModule をターゲット上の実行可能形式に変換 (コード生成) します。ターゲット翻訳結果はruntime.Moduleとしてカプセル化され、ターゲットランタイム環境でエクスポート、ロード、実行できます。
  • ランタイム実行: ユーザーは、runtime.Module をロードし、サポートされているランタイム環境でコンパイルされた関数を実行します。

モデルの調整

TVM ユーザー チュートリアルは、モデルのコンパイルと最適化の方法から始まり、TE、TensorIR、Relay などの下位レベルの論理構造コンポーネントに徐々に進みます。

ここでは、AutoTVM を使用してモデルを自動的に調整する方法と、TVM によるモデルのコンパイル、調整、実行のプロセスを実際に理解する方法についてのみ説明します。原文  Python インターフェースを使用したモデルのコンパイルと最適化 (AutoTVM)  

TVMの準備

まず、TVMをインストールします。 TVM のインストールに関するドキュメント、または TVM のインストールに関する注記を参照してください。

その後、TVM Python API を使用してモデルを調整できます。まず、次の依存関係をインポートします。

 onnx をインポートする
tvm . contrib . download からdownload_testdata をインポート
PIL インポート画像から
numpyをnp としてインポートする
tvm . relay をリレーとしてインポートする
tvm をインポート
tvm.contrib からgraph_executor をインポートします

モデルを準備してロードする

事前トレーニング済みの ResNet-50 v2 ONNX モデルを取得してロードします。

 model_url = "" . join (
[
「https://github.com/onnx/models/raw/」
「メイン/ビジョン/分類/resnet/モデル/」
"resnet50-v2-7.onnx"
]


model_path = download_testdata ( model_url"resnet50-v2-7.onnx"module = "onnx" )
onnx_model = onnx.load ( model_path ) です

画像の準備と前処理

テスト画像を取得し、224x224 NCHW 形式に前処理します。

 img_url = "https://s3.amazonaws.com/model-server/inputs/kitten.jpg"
img_path = download_testdata ( img_url"imagenet_cat.png"モジュール= "data" )

# 224x224 サイズを変更します
resized_image = 画像.open ( img_path ) .resize ( ( 224,224 ))
img_data = np . asarray ( resized_image ). astype ( "float32" )

# 入力画像HWC レイアウトです ONNXはCHW 入力を期待しているので 配列変換します
img_data = np . transpose ( img_data , ( 2 , 0 , 1 ))

# ImageNet 入力仕様に従って正規する
imagenet_mean = np . 配列([ 0.485 , 0.456 , 0.406 ] ). reshape (( 3 , 1 , 1 ))
imagenet_stddev = np . 配列([ 0.229 , 0.224 , 0.225 ] ). reshape (( 3 , 1 , 1 ))
norm_img_data = ( img_data / 255 - imagenet_mean ) / imagenet_stddev

# 4 次元入力を想定しているため バッチ次元追加します: NCHW
img_data = np . expand_dims ( norm_img_dataaxis = 0 )

TVMリレーを使用してモデルをコンパイルする

TVM は ONNX モデルを Relay にインポートし、TVM グラフ モデルを作成します。

 ターゲット= 入力( "ターゲット [llvm]: " )
ターゲットでない場合:
ターゲット= "llvm"
# ターゲット= "llvm -mcpu=core-avx2"
# ターゲット= "llvm -mcpu=skylake-avx512"

# 入力モデルの種類によって異なる場合がありますツール使用できます
# 入力をチェックするNetron ような
input_name = "データ"
shape_dict = { input_name : img_data . shape }

modparams = relay.frontend.from_onnx (onnx_model shape_dict )

tvm.transform.PassContext ( opt_level = 3 ) 場合:
lib = リレー.build ( modtarget = ターゲットparams = パラメータ)

dev = tvm . デバイス( str ( ターゲット), 0 )
モジュール= graph_executor.GraphModule ( lib [ " default" ] ( dev ))

 ターゲット ターゲットハードウェアプラットフォームです。   llvm  使用される CPU を参照します。パフォーマンスを最適化するには、アーキテクチャ命令セットを指定することをお勧めします。 CPU を表示するには、次のコマンドを使用できます。

 $ llc --version | grep CPU
ホストCPU : skylake
$ lscpu

または、製造元の Web サイト (Intel® 製品など) に直接アクセスして、製品パラメータを表示します。

TVMランタイムを使用してモデルを実行する

TVM ランタイムでモデルを実行し、予測を行います。

 dtype = "float32"
モジュール.set_input ( input_name , img_data )
モジュール.run ()
出力形状= ( 1 , 1000 )
tvm_output = module.get_output ( 0 , tvm.nd.empty ( output_shape ) ) . numpy ( )

最適化の前にパフォーマンスデータを収集する

最適化の前にパフォーマンス データを収集します。

 インポートtimeit

タイミング番号= 10
タイミングリピート= 10
最適化されていない= (
np . array ( timeit . Timer ( lambda : module . run () ). repeat ( repeat = Timing_repeatnumber = Timing_number ))
* 1000
/ タイミング番号

最適化されていない= {
「平均」 : np . 平均( 最適化されていない)、
「中央値」 : np . 中央値( 最適化されていない)、
"std" : np . std ( 最適化されていない)、
}

印刷( 最適化されていない)

その後、最適化後のパフォーマンスを比較するために使用されます。

予測結果を得るための後処理出力

出力された予測結果は、読み取り可能な分類結果に後処理されます。

 scipy から. special import softmax

# ラベルリストダウンロードする
labels_url = "https://s3.amazonaws.com/onnx-model-zoo/synset.txt"
labels_path = download_testdata ( labels_url"synset.txt"module = "data" )

open ( labels_path , "r" ) f として:
ラベル= [ l . rstrip () lf 入れる ]

# 出力開いて出力テンソル読み取ります
スコア= ソフトマックス( tvm_output )
スコア= np . squeeze ( スコア)
ランク= np . argsort ( スコア)[:: - 1 ]
順位[ 0 : 5 ] :
print ( "クラス='%s'、確率=%f" % ( ラベル[ 順位]、 スコア[ 順位]))

モデルを調整し、調整データを取得する

AutoTVM を使用して、ターゲット ハードウェア プラットフォームを自動的に調整し、調整データを取得します。

 tvm . auto_scheduler をauto_scheduler としてインポートします
tvm.autotvm.tuner からXGBTuner インポート
tvm からautotvm をインポート

= 10
繰り返し= 1
min_repeat_ms = 0 # CPU でチューニングしているので 0 に設定できます
タイムアウト= 10 # 単位

# TVM ランナー作成する
ランナー= autotvm.LocalRunner (
=
繰り返し= 繰り返し
タイムアウト= タイムアウト
min_repeat_ms = min_repeat_ms
enable_cpu_cache_flush = True


チューニングオプション= {
「チューナー」 : 「xgb」
「トライアル」 : 10 ,
「早期停止」 : 100
"測定オプション" : autotvm . 測定オプション(
ビルダー= autotvm . LocalBuilder ( build_func = "default" )、 ランナー= runner
)、
"チューニングレコード" : "resnet-50-v2-autotuning.json"
}

# onnx モデルからタスク抽出することから始めます
タスク= autotvm . task . extract_from_program ( mod [ "main" ]、 ターゲット= targetパラメータ= params )

# 抽出されたタスク順番にチューニングします
i の場合タスクenumerate ( タスク) します。
prefix = "[タスク %2d/%2d] " % ( i + 1 , len ( タスク))
tuner_obj = XGBTuner ( タスクloss_type = "rank" )
tuner_obj . チューン(
n_trial = min ( tuning_option [ "trials" ], len (task.config_space ) ),
early_stopping = チューニングオプション[ "early_stopping" ],
measure_option = チューニングオプション[ "measure_option" ],
コールバック= [
autotvm.callback.progress_bar ( tuning_option [ "trials" ] , prefix = prefix ),
autotvm . callback . log_to_file ( tuning_option [ "tuning_records" ]),
]、


その上 チューニングオプション オプション  XGBoost グリッド アルゴリズムは最適化された検索を実行し、データが記録されます チューニングレコード 

モデルを再コンパイルし、調整されたデータを使用する

チューニング データに基づいて最適化されたモデルを再コンパイルします。

 autotvm . apply_history_best ( tuning_option [ "tuning_records" ] ) を使用する場合:
tvm.transform.PassContext ( opt_level = 3 config = {} ) の場合:
lib = リレー.build ( modtarget = ターゲットparams = パラメータ)

dev = tvm . デバイス( str ( ターゲット), 0 )
モジュール= graph_executor.GraphModule ( lib [ " default" ] ( dev ))


# 最適化されたモデルが実行され 同じ結果生成されることを確認します

dtype = "float32"
モジュール.set_input ( input_name , img_data )
モジュール.run ()
出力形状= ( 1 , 1000 )
tvm_output = module.get_output ( 0 , tvm.nd.empty ( output_shape ) ) . numpy ( )

スコア= ソフトマックス( tvm_output )
スコア= np . squeeze ( スコア)
ランク= np . argsort ( スコア)[:: - 1 ]
順位[ 0 : 5 ] :
print ( "クラス='%s'、確率=%f" % ( ラベル[ 順位]、 スコア[ 順位]))

調整済みモデルと未調整モデルの比較

最適化後のパフォーマンス データを収集し、最適化前のデータと比較します。

 インポートtimeit

タイミング番号= 10
タイミングリピート= 10
最適化= (
np . array ( timeit . Timer ( lambda : module . run () ). repeat ( repeat = Timing_repeatnumber = Timing_number ))
* 1000
/ タイミング番号

最適化= { "平均" : np . 平均( 最適化)、 "中央値" : np . 中央値( 最適化)、 "標準値" : np . 標準値( 最適化)}

print ( "最適化済み: %s" % ( 最適化済み))
print ( "最適化されていません: %s" % ( 最適化されていません))

モデルを調整するプロセス全体の結果は次のとおりです。

 $ 時間python autotvm_tune . py
# TVM コンパイルしてモデルを実行する
## ONNX モデルダウンロード読み込み
## テストイメージのダウンロード 前処理 読み込み
## Relay モデルコンパイルする
ターゲット[ llvm ]: llvm - mcpu = core - avx2
1 つ以上演算子調整されてませんパフォーマンスを向上させるにはモデル調整してください詳細表示するには、 DEBUG ログレベルを使用してください
## TVM ランタイム実行
## 基本的なパフォーマンスデータを収集する
{ '平均' : 44.97057118016528'中央値' : 42.52320024970686'標準偏差' : 6.870915251002107 }
## 出力後処理する
クラス= 'n02123045 トラ猫、トラ猫' 確率= 0.621104
クラス= 'n02123159 トラ猫' 確率= 0.356378
クラス= 'n02124075 エジプト猫' 確率= 0.019712
クラス= 'n02129604 トラ、Panthera tigris' 確率= 0.001215
クラス= 'n04040759 ラジエーター' 確率= 0.000262
# AutoTVM がモデルを調整します[ Y / n ]
モデル調整する
[ タスク1/25 ] 現在/ 最高: 156.96 / 353.76 GFLOPS | 進行状況: ( 10/10 ) | 4.78 完了
[ タスク2/25 ] 現在/ 最高: 54.66 / 241.25 GFLOPS | 進行状況: ( 10/10 ) | 2.88 完了
[ タスク3/25 ] 現在/ 最高: 116.71 / 241.30 GFLOPS | 進行状況: ( 10/10 ) | 3.48 完了
[ タスク4/25 ] 現在/ 最高: 119.92 / 184.18 GFLOPS | 進行状況: ( 10/10 ) | 3.48 完了
[ タスク5/25 ] 現在/ 最高: 48.92 / 158.38 GFLOPS | 進行状況: ( 10/10 ) | 3.13 完了
[ タスク6/25 ] 現在/ 最高: 156.89 / 230.95 GFLOPS | 進行状況: ( 10/10 ) | 2.82 完了
[ タスク7/25 ] 現在/ 最高: 92.33 / 241.99 GFLOPS | 進行状況: ( 10/10 ) | 2.40 完了
[ タスク8/25 ] 現在/ 最高: 50.04 / 331.82 GFLOPS | 進行状況: ( 10/10 ) | 2.64 完了
[ タスク9/25 ] 現在/ 最高: 188.47 / 409.93 GFLOPS | 進行状況: ( 10/10 ) | 4.44 完了
[ タスク10/25 ] 現在/ 最高: 44.81 / 181.67 GFLOPS | 進行状況: ( 10/10 ) | 2.32 完了
[ タスク11/25 ] 現在/ 最高: 83.74 / 312.66 GFLOPS | 進行状況: ( 10/10 ) | 2.74 完了
[ タスク12/25 ] 現在/ 最高: 96.48 / 294.40 GFLOPS | 進行状況: ( 10/10 ) | 2.82 完了
[ タスク13/25 ] 現在/ 最高: 123.74 / 354.34 GFLOPS | 進行状況: ( 10/10 ) | 2.62 完了
[ タスク14/25 ] 現在/ 最高: 23.76 / 178.71 GFLOPS | 進行状況: ( 10/10 ) | 2.90 完了
[ タスク15/25 ] 現在/ 最高: 119.18 / 534.63 GFLOPS | 進行状況: ( 10/10 ) | 2.49 完了
[ タスク16/25 ] 現在/ 最高: 101.24 / 172.92 GFLOPS | 進行状況: ( 10/10 ) | 2.49 完了
[ タスク17/25 ] 現在/ 最高: 309.85 / 309.85 GFLOPS | 進行状況: ( 10/10 ) | 2.69 完了
[ タスク18/25 ] 現在/ 最高: 54.45 / 368.31 GFLOPS | 進行状況: ( 10/10 ) | 2.46 完了
[ タスク19/25 ] 現在/ 最高: 78.69 / 162.43 GFLOPS | 進行状況: ( 10/10 ) | 3.29 完了
[ タスク20/25 ] 現在/ 最高: 40.78 / 317.50 GFLOPS | 進行状況: ( 10 / 10 ) | 4.52 完了
[ タスク21/25 ] 現在/ 最高: 169.03 / 296.36 GFLOPS | 進行状況: ( 10/10 ) | 3.95 完了
[ タスク22/25 ] 現在/ 最高: 90.96 / 210.43 GFLOPS | 進行状況: ( 10/10 ) | 2.28 完了
[ タスク23/25 ] 現在/ 最高: 48.93 / 217.36 GFLOPS | 進行状況: ( 10/10 ) | 2.87 完了
[ タスク25/25 ] 現在/ 最高: 0.00 / 0.00 GFLOPS | 進行状況: ( 0/10 ) | 0.00 完了
[ タスク25/25 ] 現在/ 最高: 25.50 / 33.86 GFLOPS | 進行状況: ( 10/10 ) | 9.28 完了
## チューニングデータを使用して最適化されたモデルコンパイルする
クラス= 'n02123045 トラ猫、トラ猫' 確率= 0.621104
クラス= 'n02123159 トラ猫' 確率= 0.356378
クラス= 'n02124075 エジプト猫' 確率= 0.019712
クラス= 'n02129604 トラ、Panthera tigris' 確率= 0.001215
クラス= 'n04040759 ラジエーター' 確率= 0.000262
## 調整済みモデル未調整モデルの比較
最適化: { '平均' : 34.736288779822644'中央値' : 34.547542000655085'標準偏差' : 0.5144378649382363 }
最適化されていない: { '平均' : 44.97057118016528'中央値' : 42.52320024970686'標準偏差' : 6.870915251002107 }

3 分23 904
ユーザー5 m2 .900 s
システム5 分 37 099

パフォーマンス データを比較すると、調整されたモデルがより高速かつスムーズに実行されることがわかります。

<<:  分散フロー制御アルゴリズムを5分で理解する

>>:  自動運転車がコーナーを「見通し」できるようにする

ブログ    
ブログ    
ブログ    
ブログ    

推薦する

Googleを超えろ!世界最大の時間結晶が記録を破り、量子コンピューターが新たな奇跡を起こす

今日、タイムクリスタルは再び新しいスターを迎え、Sceinceサブマガジンに登場しました。 タイムク...

年齢を測るAI顔認識

Instagramは、顔をスキャンして年齢を推定できるサードパーティ企業Yotiが開発したAIツール...

初心者向けガイド: 機械学習とディープラーニング

ウェッジ:機械学習とディープラーニングは現在注目されており、突然多くの人がそれについて話していること...

建設業界はAIとIoTの次の大きなターゲット

建設業界は、革新、破壊、あるいは何と呼ぼうと、何らかの変化が起こりやすい時期にあります。以前にも書い...

コーチや監督者になる...人間と機械のコラボレーションにより、AIはあなたをよりよく理解します

一見退屈で冷淡なアルゴリズムは、継続的な反復とアップグレードを経て、外界を認識でき、人間の意思決定を...

...

AppleがAI研究成果を公開、マルチモーダルLLMモデルFerretをリリース

IT Homeは12月25日、Appleがコロンビア大学の研究者らと協力して2023年10月にオープ...

ChatGPTはユーザーがペイウォールを回避できないようにBing検索へのアクセスを停止

7月5日のニュース、6月28日、OpenAIのチャットボットChatGPTは、MicrosoftのB...

人工知能は祝福か、それとも呪いなのか?

ますますペースが速まるこの時代において、私たちは効率性を高め、ブレークスルーを追求し続けています。多...

アダプティブコンピューティングがAI製品化の課題にどのように対処するか

[[389356]]今日、人工知能技術は急速に発展しており、イノベーションのペースは加速しています。...

...

Kingsoft ビデオクラウド AI + エッジコンピューティング デュアルアクセラレーションが 5G HD 時代をリード

5G時代の到来により、さまざまな業界のトラフィックが爆発的な増加を遂げており、特にビデオ業界はインタ...

...

あなたのプライベートな写真が「合法的に」閲覧される可能性があります。顔認識を使用するときは必ず服を着用してください。

本日7月3日、デジタルブロガーの@长安数码君がソーシャルプラットフォームでニュースを発表しました。顔...

大規模モデルの微調整には人間のデータに頼らなければならないのでしょうか? DeepMind: フィードバック付きの自己トレーニングの方が優れている

皆さんもご存知のとおり、大規模言語モデル (LLM) はディープラーニングの状況を変えつつあり、人間...