序文
現在のAIブームは単なるコンピューティングパワーの産物にすぎないと言う人もいます。現在、さまざまな大規模なモデルや大規模なトレーニング セットが際限なく出現し、複雑かつ精巧なテクノロジーを使用して、リーダーボードのスコアを継続的に更新しています。これらの人々は、あることを忘れているようです。いずれは AI モデルが実装され、使用されるでしょう。そこに行くことと、象牙の塔に彫刻を注意深く彫ることとの違いは何でしょうか?ハードウェア アクセラレーションをサポートする使いやすいフレームワークは数多くありますが、GPU のコストが高く、メーカーが開発した NPU などのフレームワークの複雑さは依然として存在します。そこでこの記事は、グラフィック カードを買う余裕がなく、5 年前のインテルのローエンド CPU しか持っていない貧乏人だが、流行のスタイルもプレイしたいという素朴で素敵なアイデアから始めます。 GAN を転送します。どうすればよいですか?管理しますか?
環境
まず初めに、この記事の主人公 No. 1 へようこそ。私たちのスタイル トランスファー モデル xxx.onnx:
プライバシー保護のため、主人公の名前はここでは公開できません。入力と入力を通じてのみ垣間見ることができます。出力。
入力が 1,?,?,3、出力が ?,?,?,3 であることがわかり、onnx の標準入力形状 ncwh とは異なる nhwc 入力であることが確認できます。これはパフォーマンスに影響すると言われていますが、推論ではありますが、測定はされていません。また、?記号は動的入力を示し、このモデルの入力と出力に固定された形状がないことを示します。それでも理解できない場合は、次のようにモデルに画像を挿入し、モデルから画像を取り出します。
元の画像:
生成された画像:
それでは、この記事の主人公 2 号、私たちの高貴な Pentium CPU:
最後に、この記事の主人公その3:
python3.10.6
Onnxruntime1.14.0
加速する
1. ベンチマーク
import onnxruntime as ort
options = ort.SessionOptions()
options.enable_profiling = True #记录性能开关
result = session.run(None, {
x: img})[0] #运行推理
prof_file = session.end_profiling() #推理结束后结束日志
まず、推論速度に関する基本的なテストを行う必要があります。タイミングのコードに複数の time.time() を挿入した後、ONNX の各層の計算時間を詳細に確認する必要がある場合は、次を使用する必要があります。提供するプロファイリング機能です。方法は非常に簡単です。スイッチをオンにし、推論が終了したら記録を終了すると、同じディレクトリに onnxruntime_profile_XXXX-XX-XX_XX-XX-XX.json ファイル。結果は次のとおりです。
ボトルネックは推論であり、推論に 9.37 秒かかったことがわかります。それでは、どの演算子がそれほど時間がかかるのでしょうか? 次のコードを含む json ファイルを表示します。
import json
with open('onnxruntime_profile__2023-03-02_10-23-47.json', "r") as f:
sess_time = json.load(f)
l = sorted(sess_time, key=lambda k: k['dur'], reverse=True)
per = 0
total = l[0]['dur']
for x in l[2:52]:
print(x['dur'])#打印持续时间
print(x['args'])#打印具体参数
per+=x['dur']
print(f'Top50 total is {
per/total*100:.2f}%')
このコードは、最も時間のかかる演算子の上位 50 [2:52] を出力し、その割合を示します。最初の 2 つは合計時間を指すため、ここでは除外されます。結果は次のとおりです。
例外なくすべてヘイトな Conv レイヤーであり、畳み込みには非常に時間がかかることに注意してください。
次に、もう一度実行して、今度はハードウェアの使用状況を確認します。
このような時間のかかる畳み込み層の場合、CPU は実際には怠惰です。
2. CPU の遅延の問題を解決します。
前のコードに引き続きオプションを追加し、使用するスレッドの数を 4 に調整します。私の CPU には 2 コアと 4 スレッドがあるため、いっぱいになる可能性があります。じっくり使って、改善があるかどうかを確認してください。
options.intra_op_num_threads = 4
今はいっぱいです:
効果は次のとおりです。
改善効果は明らかで、改善は約 1 秒です。9.3→7.7。
3. ONNXRUNTIME 自体の最適化をオフにする
options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_DISABLE_ALL
デフォルトでは、すべての最適化が有効になっていますが、これをオフにすると、代わりにパフォーマンスが向上することがわかりました。
7.7->7.0、さらに 0.7 秒速くなりました。後で GPU でテストした結果、最適化により GPU にはわずかな加速効果がありますが、CPU には副作用であることがわかりました。
4. 固定サイズ + 量子化前の前処理
ここでは、画像を 1280x720 の解像度にスケーリングしたと仮定します。
まず入力ベクトルのサイズを 1,720,1280,3 に固定します。
python -m onnxruntime.tools.make_dynamic_shape_fixed --input_name xxx --input_shape 1,720,1280,3
次に、量子化の前に前処理、つまりサイズの推論と最適化を行います。
python -m onnxruntime.quantization.preprocess --input xxx.onnx --output xxx_preprocessed.onnx
もう一度実行してみると、
7.0 秒から約 6 秒と、1 秒も速くなっていることがわかりました。
要約する
この例では、いくつかのトリックを使用して、壊れた CPU の推論速度を 3 秒高速化することに成功し、33% のパフォーマンス向上が得られました。この向上は十分に大きくないように見えるかもしれませんが、生成のプロセスでいくつかのコストを節約できることを意味します。バッチ画像 時間。個人的には、すべての AI モデルが非常に低コストで優れたパフォーマンスに基づいて、AI モデルの迅速な実装と普及を促進し、一般の人々が技術独占を打ち破ることができるようになることを強く望んでいます。
述べる
opset_version と量子化を変更するとパフォーマンスが向上する可能性もありますが、この例ではどちらも明らかではなく、量子化後はパフォーマンスがマイナスに向上します。誰かが必要とするかもしれないので、ここに 2 つのリンクを貼ってください:
opset_version
量子化モデルを int8 に変更します。