寝る前に実装して実行したところ、実行時間が逆に遅くなったので、その原因を見つけるために見直していました。
結果としては最大ワークグループ数(512)と処理のブロック化係数(256)の取り扱いを混同していたために、(無駄な処理を行って)実行時間が伸びていました。結構情けないw
途中でブロック化係数を512にすれば早くなるのでは?という気持ちもあり余計混同してしまったようです…ほんとに情けないw
原因が見つかったので、さっそく512x512サイズの結果を見てみると…
[INFO ] stable-diffusion.cpp:4064 - latent 1 decoded, taking 93.23s
[INFO ] stable-diffusion.cpp:4068 - decode_first_stage completed, taking 93.23s
[INFO ] stable-diffusion.cpp:4492 - generate_image completed in 712.10s
と言う結果が、
[INFO ] stable-diffusion.cpp:4064 - latent 1 decoded, taking 81.16s
[INFO ] stable-diffusion.cpp:4068 - decode_first_stage completed, taking 81.16s
[INFO ] stable-diffusion.cpp:4492 - generate_image completed in 697.35s
と言う結果になりました。
数字的には、93.23s - 81.16s = 12.07s という結構に。確実なインパクトがありました。
いつもながらまともな環境でCUDAとかなら単位が変わるので10ミリ秒程度の差になるかと…w
しかも何回か他の部分でも呼び出されていた結果、全体の実行時間でも効果が出ています。
712.10s - 697.35s = 14.75s
14.75s - 12.07s = 2.68s
内部の処理でも2秒も差が出ています。処理としては単純コピーの処理ですが、これだけの差が…。
今回実行中に知りましたが、最大ワークグループ数についてなんとなく意識はしていましたが、思っていた以上に大きな意味があるようで…エラーも結構細かく出してきます。
The number of work-items in each dimension of a work-group cannot exceed {512, 512, 512} for this deviceException caught
このデバイスでは、ワークグループの各次元におけるワークアイテムの数は{512, 512, 512}を超えることはできません。例外が発生しました。 (グーグル翻訳)
なるほど、各次元ごとにワークアイテムと言う単位で処理してると…
こんなことを意識していると面白くなってきたので、ブロック化係数を最大の512にしてみました。
すると…遅くなりました。解せぬw
[INFO ] stable-diffusion.cpp:4064 - latent 1 decoded, taking 142.24s
[INFO ] stable-diffusion.cpp:4068 - decode_first_stage completed, taking 142.24s
[INFO ] stable-diffusion.cpp:4492 - generate_image completed in 762.72s
CPU4コアと同じぐらいの速度に。最大値に近づいて遅くなったので、今度は小さくして試してみました。
結構衝撃的な現実が見えてきます…
| ブロック化係数 | vae実行時間 | 全体の実行時間(参考値) |
|---|---|---|
| 512 | 142.24s | 762.72s |
| 256 | 81.16s | 697.35s |
| 128 | 50.88s | 667.42s |
| 64 | 36.12s | 653.10s |
| 32 | 30.71s | 655.82s |
| 16 | 29.98s | 657.95s |
| 8 | 36.39s | 662.30s |
全体の実行時間はプロンプトを若干変更して実行しているのであくまでも参考値です。
なんと…ロジックを弄るより、ブロック化係数を変更した方が劇的に影響が出ました。正直なところ理解を超えた結果です。
SYCLのドキュメントの節々で小規模単位で処理を行わせようとしている理由が少しわかった気がします。
vaeの実行時間だけ見れば、処理単位のブロック化係数を変更するだけで、なんと4.74倍、約5倍程度の差が出ています。
あくまでも、ブロック化係数を正しく実装されている場合に限りますが、最適化されていない状態であるとするならば、処理時間が5分の1になるという可能性を秘めているという事です。70分かかっているものが、 14分で出来上がるという事です。まぁこの数字は希望的数字ですが(笑)
今回、手を入れた処理は単純コピーで、内部コードでハマる命令が実行された結果の産物だとは思いますが、それでもブロック化係数が大きくても(ブラックボックスながらGPUに対して)考えられる知識を前提に実装したつもりですが、それ以上に処理単位を細分化することによる恩恵が大きいという事でしょうか…
今まで処理単位について一括で処理できれば大きい方が絶対的な有利だと信じていた部分がありますが、現実には適切な大きさにしてバランスを考えることが必要だという事なのでしょう。
正直こんなことここまで考えたことは無かったのですが、面白い結果を得ることができました。
0 件のコメント:
コメントを投稿