動的形状の検出 

https://www.intel.com/content/www/us/en/developer/articles/training/detecting-dynamic-shapes.html 

モデルの動的データと操作を特定し、動的形状を抑えてパフォーマンス向上につなげる方法
https://github.com/HabanaAI/Gaudi2-Workshop/tree/main/Detecting-Dynamic-Shapes

＜動的形状とその検出方法＞
動的形状は、動的な入力データや演算子がどのように可変出力 Tensor 形状の生成に影響するかに基づいてモデルの挙動を記述します。
通常は動的形状によって再コンパイルが発生し、実行速度が遅くなります。モデルの速度を最適化するには、1) 動的な入力や操作がないかを特定し、2) 動的形状の処理に記載されている手順に従って可能であれば抑えたほうが望ましいとされます。
https://docs.habana.ai/en/latest/PyTorch/Model_Optimization_PyTorch/Dynamic_Shapes.html

ここでは動的な入力と操作を検出するツールを取り上げて説明します。

＜動的特性のタイプ＞
動的形状は大きく 2 つに分類できます。
•入力 – 言語モデルの可変長センテンスや画像モデルの解像度の違いなど、学習処理中の入力形状の違いにより発生する動的形状。
•操作 – 出力形状が、入力形状だけではなく、実際の入力データに依存する特定の操作により発生する動的形状。つまり、特定の入力形状に対し推論不可の出力形状を持つ操作。

＜動的特性を検出する＞
モデルの動的特性を検出するには、通常の再コンパイルの確認に、インテル® Gaudi® アクセラレーター製品の動的形状自動化サポート機能を使用します。
•以下のとおり、環境フラグを設定します。PT_HPU_METRICS_FILE=/root/metricslog.json PT_HPU_METRICS_DUMP_TRIGGERS=process_exit,metric_change
この設定により、モデルの再コンパイルについて全体を把握することができます。生成された metricslog.json ファイルが示すのは、 graph_compilation が呼び出される頻度です。静的グラフの場合、数ステップ後に再コンパイル回数の減少が期待できます。

•再コンパイルが続く場合は、PT_HPU_ENABLE_REFINE_DYNAMIC_SHAPES=1 
を設定して、インテル® Gaudi® アクセラレーター製品の動的形状自動制御を有効にします。この変数を設定することで、PyTorch ブリッジとグラフ・コンパイラーにより、モデルスクリプト内で動的形状の自動管理が有効になります。グラフにはバケット分割と一定サイズになる範囲へのパディングが自動で行われるため、再コンパイルが減少し、動的ワークロードと連動する際のパフォーマンス向上につながります。

•再コンパイルが続く、または不安定な状態になりパフォーマンスを改善したい場合は、次のセクションに進んでください。

＜モデルのデータと操作をさらに深く解析する＞
ここから先は、これらのツールをモデルの分析に使用する方法について詳しく説明します。これらのツールは動的な範囲をピンポイントで特定し、改善を図ります。

＜動的入力の検出＞
このセクションでは、Torch DataLoader を受け取り、いくつの異なる入力形状が検出されたかレポートを出力する data_dynamicity ツールを使用して、入力データセットに見られる動的特性の高低に着目します。動的特性が高い入力をパディングによって軽減する手法については、テキスト形式のデータセットを参照してください。
https://www.intel.com/content/www/us/en/developer/articles/training/detecting-dynamic-shapes.html#text-datasets

＜画像データセット＞
【動的特性が低い入力】

以下の例では、
	バッチサイズ 7
	2 つの異なる入力形状 (バッチサイズ = 7 とバッチサイズ = 3) がある MNIST データセットを使用していることが分かります (MNIST には学習対象の画像が 60000 あり、60000%7=3 から最後の 1 つがバッチサイズ = 3 となるため)。
これは入力の動的特性が非常に低く、許容可能な範囲です。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/7c894adb-07ba-40e2-bf36-95ec38334ba1.png)

このコードからの出力は次のようになり、ここでは動的特性は見られません。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/9b5193b1-6b80-4b85-ba4c-a5f7c0e6a9e9.png)

【動的特性が高い入力】
一方で、次の例で使用する Flowers 102 データセットの場合、入力形状が 29 とさまざまな形状の画像が含まれています。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/1eebaf6b-0085-4ef2-8598-05ed1897f8bd.png)

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/909e4450-6aa9-4d23-aa46-7962d444e8cf.png)

ユースケースに応じて、画像を固定サイズのバケットに分割、または 1 つの形状にリサイズ / クロップできます。次に示すのは、Flowers 102 データセットを静的にする、centre-crop ソリューションの例です。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/29b5617f-c60c-44e6-8fec-9cb74c938f99.png)

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/0bc6f3f2-cf94-41f0-a1b3-a7c999d0e536.png)

＜テキスト形式のデータセット＞
多くの場合、テキスト形式のデータセットは入力の動的特性が高く、これはセンテンス長がさまざまだからです。以下の例では、443 の異なる形状を持つ SQUAD データセットを batchsize=7 で分割しました。各バッチ内でセンテンスの最大サイズにパディングしています。

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/e241ce88-4c25-4898-9ba6-8a6009dfb901.png)

![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/64e9e6a5-767c-4aa7-acbe-ed81c1a57d47.png)

静的形状を得る簡単な方法は、最長のセンテンスにパディングすることです。ただし、この方法は演算面では効率的ではありません。パディングした部分はその後破棄されることになり、演算の手間は無駄になるからです。
次の例では、同じ SQUAD データセットを最大センテンス長にパディングしているため、入力の動的特性が低いことが示されています。

![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/76804bae-0dfb-4a42-b3f8-5a1153a50bc4.png)

![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/f5c94314-58b2-4a55-9e74-cf251b32dece.png)

バケット分割により最長センテンスにパディングすれば、コンパイル回数を減らしつつ、演算が無駄になることはありません。ここではバケット数を示すハイパーパラメーターを選択し、データセット内の最短センテンスから最長センテンスの範囲をバケットに分割するアルゴリズムを使用しました。続けて各バッチごとにバッチ内の最長センテンスを特定し、そのセンテンスよりもわずかに長いバケットにパディングしています。
wav2vec を使用した事例については、下記URLを参照してください。
https://docs.habana.ai/en/latest/PyTorch/Model_Optimization_PyTorch/Dynamic_Shapes.html#case-study-using-wav2vec2-for-dynamic-inputs-to-models

![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/c18c38ab-a4d2-495a-a51b-73b23d09159f.png)

![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/6a5fad2e-d7dd-4f4d-b436-3ee4538c5196.png)

ここまでで、モデルの入力形状は 6 タイプのみ、センテンス長をバケットに分割、各バケットを埋める最小量でパディングしたことを確認しました。

＜動的操作の検出＞
これで動的入力の検出方法が分かりましたので、次はモデルの動的操作を検出してみましょう。動的操作とは、入力形状を知るだけでは出力形状を予測できない操作を指します。
この例では、5 ステップで実行できる簡単な小型モデルを用意しました。入力形状は 4 ステップ目で変わるため、ここで再コンパイルが予測されます。ただし、モデル自体に動的操作が含まれるので、ツールがモジュールを特定し、これが動的と捉えることとします。
以下のコードサンプルは、Python ファイル (dyn_ops.py) にコピーして、Terminal で実行可能です。

![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/b11e64bf-f21c-4d5a-9e85-9d02e6f705fb.png)

detect_recompilation_auto_model ツールから 2 つの表と関連する csv ファイルが出力されます。

1 つ目は各ステップで発生すること、2 つ目は最も再コンパイル頻度の高いモジュール / サブモジュールのリストです。1 つ目の表から詳しく見ていきましょう。

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/94255c29-3b6d-480d-ba5e-3e724b56982e.png)

ステップ 0: 全モジュールに対する再コンパイル (最初の手順のため)。
ステップ 1: InnerNet と Net の再コンパイル。コメント欄に記載されているとおり、
・InnerNet の動的操作は、動的な child モジュールがなくても再コンパイルされるため。
・Net が動的ではないと言えるのは、Net の child モジュール (InnerNet) が再コンパイル済みと考えられるため。
ステップ 2: ここでは新しい入力形状が見られるため、コメント欄に記載のとおり、すべてのモジュールが再コンパイル。
ステップ 3: InnerNet に動的操作が含まれることを示し、その結果、コメント欄に記載のとおり、ツールからの考えられる出力は以下のとおり。
1.	新しい入力形状のため、再コンパイル。
2.	すでに処理済みの入力形状を再コンパイル、新しい出力形状を含み、動的操作または child モジュールによると考えられる。
3.	すでに処理済みの入力形状を再コンパイル。おそらく動的操作により発生。
4.	すでに処理済みの入力形状を再コンパイル、新しい出力形状を含み、動的操作によると考えられる。
注: なお、このツールは実行に時間がかかるため、以下の対処を推奨します。
・ステップ数を少なく抑えて実行する。
・インテル® Gaudi® アクセラレーター 1 カード上で実行する (分散しない)。
・このツールは入力による再コンパイルを検出して検出後に無視できますが、ツールの実行時間を短縮するために、同じ形状の入力内で渡すことを推奨。静的入力ならば、ツールは動的操作の検出にのみ注力できます。次の例では、動的な部分を静的に置き換えてみました。detect_recompilation_auto_model ツールを実行後は、入力からの動的特性のみが確認できます。

![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/4bd8d980-f518-4f19-90f6-e73c4d62ce72.png)

![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/8da7e927-c093-400d-bb68-edfcdabc6966.png)

＜動的セクションの検出＞
次の例では、実際のモデル Faster RCNN を使用し、モデル内の動的部分を検出してみました。

![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/172c05b6-9ef9-4d28-9df0-3d34e4e4192b.png)

この出力から、以下のことが見て取れます。

![図3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3490396/779d90cb-05d9-4115-a36e-d62853da0d17.png)

この出力から、MultiScaleRoIAlign クラスと RoIHeads クラスに動的操作が含まれていることが分かります。
MultiScaleRolAlign
https://github.com/pytorch/vision/blob/v0.15.2/torchvision/ops/poolers.py##L201

RolHeads 
https://github.com/pytorch/vision/blob/v0.15.2/torchvision/models/detection/roi_heads.py##L708


これらの部分を静的に書き換える、または CPU 操作に移行することができます。こうした手法については、動的操作の軽減手法を参照してください。
https://docs.habana.ai/en/latest/PyTorch/Model_Optimization_PyTorch/Dynamic_Shapes.html#mitigation-techniques-for-dynamic-ops

Copyright© 2023 Habana Labs, Ltd. an Intel Company.

Apache License Version 2.0 (以下「ライセンス」) の下に使用許諾条件が適用されます。
本ライセンスを遵守しない限り、このファイルを使用することはできません。本ライセンスのコピーは、以下の場所から入手できます https://www.apache.org/licenses/LICENSE-2.0。
該当する法律で義務付けられている場合または書面で合意した場合を除いて、本ライセンスの下で頒布されるソフトウェアは、明示されているか否かにかかわらず、いかなる種類の保証あるいは条件なしに「現状のまま」提供されるものとします。本ライセンスの下での許可および制限を規定する特定の文言については、本ライセンスを参照してください。