-
Notifications
You must be signed in to change notification settings - Fork 920
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix import and make npz for alpha_mask #1632
Conversation
@@ -2514,6 +2518,7 @@ def cache_batch_latents( | |||
if image.shape[2] == 4: | |||
alpha_mask = image[:, :, 3] # [H,W] | |||
alpha_mask = alpha_mask.astype(np.float32) / 255.0 | |||
alpha_mask = alpha_mask[:image.shape[0] // 8 * 8, :image.shape[1] // 8 * 8] # Without rounding down [H, W], Tensor sizes may not match, so stack the tensors. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
この変更では、alpha_maskの解像度を8の倍数にround downします。
これによって、画像サイズによっては、training stepループ中にtensor sizeの不一致を解消して、スタックしないようにできます。
結果として、保存されるnpzのalpha_maskサイズは8の倍数になります。
@@ -2207,7 +2207,11 @@ def is_disk_cached_latents_is_expected(reso, npz_path: str, flip_aug: bool, alph | |||
if alpha_mask: | |||
if "alpha_mask" not in npz: | |||
return False | |||
if (npz["alpha_mask"].shape[1], npz["alpha_mask"].shape[0]) != reso: # HxW => WxH != reso |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
checking validityにおいて、
前述の変更により、alpha_maskが8の倍数になるため、このチェック判定式は使えません。
そのため、後述の変更を加えました。
if (npz["alpha_mask"].shape[1], npz["alpha_mask"].shape[0]) != reso: # HxW => WxH != reso | ||
alpha_mask_size = npz["alpha_mask"].shape[0:2] | ||
if alpha_mask_size[0] != alpha_mask_size[0] // 8 * 8 or alpha_mask_size[1] != alpha_mask_size[1] // 8 * 8: # ...is legacy caching scheme without rounding to divisible by 8 | ||
return False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
まず、npzチェック行程において、後方互換性を確保するため、
まず、8でround downしていない旧方式で作成したnpzに出会った場合、
npzを再作成させます。
この変更を行わずに、古いキャッシュを削除するよう口頭で周知する方法もありますが、
おそらく伝わりにくい情報だと思いますので、自動判定させるようにしました。
将来的には削除した方が良いかもしれません。
(もし想定外の不具合報告が発生した場合は削除しましょう)
if alpha_mask_size[0] != alpha_mask_size[0] // 8 * 8 or alpha_mask_size[1] != alpha_mask_size[1] // 8 * 8: # ...is legacy caching scheme without rounding to divisible by 8 | ||
return False | ||
alpha_mask_size = (alpha_mask_size[0] // 8, alpha_mask_size[1] // 8) # Resize alpha_mask to 1/8 scale, the same as latents | ||
if alpha_mask_size != expected_latents_size: # HxW |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
この変更では、新しいalpha_mask_sizeの判定式と比較するように補正しました。
また、この前後の行と同じように、resoではなくexpected_latents_sizeと比較するようにして、コードの視認性を向上しました。
※機能的にはresoでもexpected_latents_sizeでも同一
Here's a thought about one other issue, could we consider using the vector DB format to store cached latent instead of npz? |
Hmm, I don't think using lance is a better way. Because we are storing latent data, we can expect very little compression of the data. Also, since access is direct by file name, no vector search is required. Saving to .npz may not be the best solution, but I think it's simple and sufficient. |
pull requestを作成していただき、ありがとうございます。以下の部分で.npzファイルに保存されるalpha_maskのサイズは必ずlatentと同じサイズ(つまり8の倍数)になっていると理解していますが、そうでない場合が起きえる、ということですね。 sd-scripts/library/train_util.py Lines 2508 to 2521 in 0b7927e
なお、latentsのキャッシュ回りはsd3ブランチで大きく変えていますので、修正いただいたコードをマージできない(sd3ブランチでは削除されている)可能性もありますのでご了承ください。 |
承知しました。 一方で、 |
確認が完了しました。 |
こちらの不具合をマージ前に再現しようとしたのですが、どうも再現できませんでした。以下のようなdataset設定の.tomlを作ることで再現できると考えたのですが、認識相違ありませんでしょうか。
もし再現条件がお分かりになりましたらお教えください。よろしくお願いいたします。 |
その条件に加えて、 参考として、検証手順を下記に整理しました。 1.画像の準備 datasets.subsets_1:alpha_maskを適用する画像群:1フォルダ以上 datasets.subsets_2:alpha_maskを適用しない画像群:1フォルダ以上 2.npzを作成 通常の学習と同じように、npzを作成する。 ただし、dataset_subsets1、2は、それぞれ個別にsdxl_train.pyを実行して作成する。 3,dataset_subsets1、2両方でtraining roop実行 bucket_no_upscaleはOFFにしてください。 4.その他の設定 ・SDXL、OFT |
詳細にありがとうございます。現状、.tomlのdatasetのalpha_mask設定がすべて同一になる不具合があるため、あらかじめ分けて.npzを生成しておかないと事象が発生しない、ということですね。 恐らくですが、同じbucketに割り当てられ、かつサイズが異なる画像が、それぞれalpha_maskありとなしの両方のsubsetに存在する、というのが条件になりそうです。 手順に従い、検証してみます。 |
不具合を再現するためにも、こちら不具合の方に先に対応したほうが良さそうでしたので、サブセット間でalpha_maskの値が異なっても.npzが正しく作成されるよう修正しました。 これにより.npzがalpha_mask有り無しとも正しく生成されるようになりましたが、.npz内のalpha_maskが8で割り切れる数になっており、依然としてこの不具合が発生しないようです。 お手数ですが、最新のdevブランチでこちらの不具合が発生するか、ご確認いただくことは可能でしょうか。 |
ありがとうございます。 一方で、8で割り切れないalpha_maskは依然として発生します。 下記は問題となる画像のnpzの中身を出力したものです。
元の画像サイズは,H1461 ✕W1000で、 それ以外の画像についても、8の倍数ではないが、4の倍数であることがほとんどです。 |
どの画像が問題かがようやくわかったので、 bucket_size’(reso)が、alpha_mask値に波及しているらしく、 def select_bucket ー train_util.pyの239行目
を出力すると、下記でした。 |
(768,1124)というbucketが発生した原因は、 min_size=100 train_util.pyの217行目 make_bucket_resolutions関数において、 この状態でアスペクト比1:1でない画像を使用してしまった結果、bucket list(上記)の中から8の倍数でないbucketが選択(有効化)され、それを参照したalpha_maskがstackとして顕在化してしまったようです。 model_util.pyにおけるmin_size, height, widthのいずれかを、8,64,reso_steps ( = divisible )のいずれかに丸める処理を追加するのが良いと考えていますが、いかがでしょうか。 |
調査いただき、ありがとうございます。min_bucket_reso/max_bucket_resoにbucket_reso_stepsで割り切れない値を設定されることは、想定外でした。 bucket_reso_stepsを確認するverify_bucket_reso_stepsメソッドがありますので、メソッド名を変更して、min/max_bucket_resoについても確認しbucket_reso_steps単位に丸める処理を入れるのが良さそうです。 sd-scripts/library/train_util.py Lines 2181 to 2183 in ce49ced
sd-scripts/library/train_util.py Lines 970 to 974 in ce49ced
また一部の学習スクリプトが、このメソッドを呼んでいない潜在バグがあるので、そちらの追加も必要そうです。 |
それが最善だと思います。 ドキュメントやtrain_utilのパラメータ解説は十分に読んだつもりだったのですが、min_bucket_resoの設定ルールを理解しないまま適当に設定していました。私の使い方の方にも問題があったように思います。 追加イメージ:
|
こちらこそ、恐らくどこにも書いていないと思いますので申し訳ありません。helpテキストにも追加が必要ですね。 よろしければこちらのPRはcloseさせていただき、min/max_bucket_resoをbucket_reso_steps単位に丸める処理その他を私の方で追加しようかと思いますが、いかがでしょうか。 |
OKです。 |
min/max_bucket_resoをbucket_reso_steps単位に丸める処理を追加し、ヘルプのテキスト等は割り切れる値を指定するよう修正しました(実際には警告を出しつつ動きますが)。 verify_bucket_reso_stepsはbucketの作成後の検証だったため、DataSetクラスのコンストラクタ内でチェックと丸めを行うようにいたしました。 不具合などありましたらご連絡ください。問題提起いただき、本当にありがとうございました。 |
本件は、alpha_maskに関する潜在的な問題の修正です。
現行コードの問題点
従来、npz内のalpha_maskはbucket_sizeに応じてリサイズされます。
cache_latentsは8の倍数に丸められるが、
npz内のalpha_maskは8の倍数になっていませんでした。
その結果、画像によっては、training stepループ中にtensor sizeの不一致が発生し、スタックします。
for example:alpha_mask=(H:W)=(996:896), required_size = (992:896)
Error message:
発生条件
・alpha_maskを使用
・cache_to_diskを使用
・imageのaspect ratioが1:1でない、かつ特定のサイズ
・SDXL (おそらくモデルの種類は関係ない)
変更点
stackしないように、npzのalpha_maskを8で割り切れる値に切り捨てた。
alpha_mask = image[:image.shape[0] // 8 * 8, :image.shape[1] // 8 * 8, 3]
詳細は下記のコメントをご覧ください。