0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Wan2.2のtimestep境界0.875はどこから来たのか?

Posted at

timestep境界0.875

Wan2.2は前半にhigh noiseモデルを使用し、後半にlow noiseモデルを使用する。
このモデル切り替えのtimestepタイミングとしてしばしば0.875という数字を見かける。

# inference
t2v_A14B.sample_shift = 12.0
t2v_A14B.sample_steps = 40
t2v_A14B.boundary = 0.875

This correspond to the diffusion timestep around which the model used is supposed to start using the low noise expert. For Wan 2.2 T2V, this value should be 0.875, For Wan 2.2 I2V, the value should be 0.900. Using other values might still work.

@yuduan
The boudary is the same as the original model, i.e., 0.875 / 875 for T2V, 0.9 / 900 for I2V.

両方のモデルへのLoRAを学習する場合は、--ditに低ノイズ用モデルを、--dit_high_noiseに高ノイズ用モデルを指定します。2つのモデルは--timestep_boundaryで指定されたタイムステップで切り替わります。デフォルトはI2Vの場合は0.9、T2Vの場合は0.875です。--timestep_boundaryは0.0から1.0の範囲の値、または0から1000の範囲の値で指定できます。

けれども、この0.875がどこから出てきたのかに関して説明は皆無である。

Wan2.1の公式の図

一応、以下のような図は見られるけど数値は書かれてない。

image.png

一応、1000の7/8が875であるが、1/8(7/8)がどこから求まるかという理屈は全くもってない。

shift関数

hunyuanvideoやWan2.1ではflow shift関数が使われ、この関数は以下で示される。

t'=\frac{s\cdot t}{1+(s-1)\cdot t}

さて、この関数に適当に数値を入れて0.875となる根拠を求めたい。
$s=7,t'=0.875$を代入してみる。この時、境界のt=1/2となる。

0.875=\frac{7\cdot t}{1+6\cdot t}
t=\frac{0.875}{(7-6\cdot 0.875)}=\frac{0.875}{(7-5.25)}=\frac{0.875}{1.75}=\frac{1}{2}

ということはshift=7ならwan2.2の前半stepと後半stepの大きさは同じになるわけだ。
また、計算は省略するがI2Vの0.9は$s=9$から計算できる。

もう一回公式のshift値を見る

# inference
t2v_A14B.sample_shift = 12.0 どうして
t2v_A14B.sample_steps = 40
t2v_A14B.boundary = 0.875

というようにshift=7ではなく12である。

0.875=\frac{12\cdot t}{1+11\cdot t}
t=\frac{0.875}{12-11\cdot 0.875}=\frac{0.875}{2.375}=0.3684...

これは前半step:後半stepを$0.6316:0.3684$に分割することに相当する。
40stepならば25step:15stepとなる。これはkohya氏も指摘してる。

ComfyUIでも前半stepと後半stepが同じstepでないワークフローがあるが、大体は前半stepが後半stepより多い。(shift値が7より大きければ当然そうなるだろう)

timestep=875を通ったほうがいいのか?

一般に拡散stepはDiT(Diffusion Transformer)に通してその勾配(入力と出力の差分)を求める。
原理的には1000回DiTに通せばいいのだが、eulerでは1step分の勾配にtimestep変化分の係数をかける。例えば勾配を50倍してこれを20step分繰り返せば1000step相当の移動ができるようになる(厳密には違うかもしれないが、大体そのような理解をしている)。shift=1ではこのTimestep間隔は等間隔だが、shift>1では前半は慎重に、後半は大きく動く。

image.png

一方、前半stepと後半stepを分ける場合ではdpm++などを使うと過去の複数の勾配用いた高次補正が行われる(と思う)が、これが安定するにはちょうどモデルの切り替わるtimestep=875を通らなければいけないのではないか。もし、timestep=875を通れないなら一次近似の「euler」のほうがunipcやdpm++より多分安定するのではないか。

また例えばtimestep=880とtimestep=860を通り、timestep境界が875ならこの時の1stepの変化は厳密にはtimestepの5はhigh_noiseモデルの勾配で、15はlow_noiseモデルの勾配である。しかし、実際にはtimestep=880から860までの移動はhigh_noiseモデルの勾配で20進む。
つまり、high_noiseモデルの勾配を信じて進みすぎてしまったら(実際のlow_noiseの勾配がそれより小さかったのなら)その差分を元に立ち帰るとかどうだろうか。または880でのhigh/low両方のモデルの勾配を使って線形近似するとか。
いずれにしてもtimestep=875を通ればこの問題はないのではないだろうか?

image.png

現状、ComfyUIでtimestep=875を正確に通る条件例は以下の通りである。
●DPM++
総ステップ数が偶数 & shift=7 → ちょうど通る
shift≠7 → 通らないことが多い
●Euler
総ステップ数が奇数 & shift=7 → ほぼ通る(6.9程度にするとより近くなる)
総ステップ数が偶数 & shift=7 → 通らない

とはいえ、実際には875を厳密に通らなくても大きな問題は報告されてません。

timestep確認コード

FlowMatchEulerDiscreteSchedulerはdiffusersのものを使い、FlowDPMSolverMultistepSchedulerは以下をコピペして使う。上述の条件でtimestep=875を通るのが確認できる。

from diffusers import FlowMatchEulerDiscreteScheduler

scheduler = FlowMatchEulerDiscreteScheduler(shift=7.0)
scheduler.set_timesteps(20)
timesteps = scheduler.timesteps.tolist()
print("euler,shift=7.0,step=20,timesteps:", timesteps)
print()

scheduler = FlowMatchEulerDiscreteScheduler(shift=7.0)
scheduler.set_timesteps(21)
timesteps = scheduler.timesteps.tolist()
print("euler,shift=7.0,step=21,timesteps:", timesteps)
print()

scheduler = FlowMatchEulerDiscreteScheduler(shift=6.9)
scheduler.set_timesteps(21)
timesteps = scheduler.timesteps.tolist()
print("euler,shift=6.9,step=21,timesteps:", timesteps)
print()

scheduler = FlowDPMSolverMultistepScheduler(shift=7.0)
scheduler.set_timesteps(20)
timesteps = scheduler.timesteps.tolist()
print("dpm++,shift=7.0,step=20,timesteps:", timesteps)
print()

scheduler = FlowDPMSolverMultistepScheduler(shift=11.0)
scheduler.set_timesteps(20)
timesteps = scheduler.timesteps.tolist()
print("dpm++,shift=11.0,step=20,timesteps:", timesteps)
print()
---------------------------------------------------------
euler,shift=7.0,step=20,timesteps: [1000.0, 992.183349609375, 983.597412109375, 974.1227416992188, 963.6138916015625, 951.8916015625, 938.7329711914062, 923.8567504882812, 906.903076171875, 887.4041748046875, 864.7404174804688, 838.0731811523438, 806.2388916015625, 767.5745849609375, 719.6183471679688, 658.562744140625, 578.1918334960938, 467.6175537109375, 305.8750915527344, 46.75572204589844]

euler,shift=7.0,step=21,timesteps: [1000.0, 992.591552734375, 984.4938354492188, 975.60595703125, 965.806396484375, 954.9472045898438, 942.8468017578125, 929.279296875, 913.9608764648438, 896.529052734375, 876.5142211914062, 853.296142578125, 826.0390014648438, 793.5884399414062, 754.3040161132812, 705.7726440429688, 644.2940673828125, 563.8898315429688, 454.23089599609375, 295.80023193359375, 46.75572204589844]

euler,shift=6.9,step=21,timesteps: [1000.0, 992.4841918945312, 984.2709350585938, 975.2583618164062, 965.3238525390625, 954.318359375, 942.0587158203125, 928.3177490234375, 912.8095703125, 895.1698608398438, 874.9267578125, 851.4580688476562, 823.9259643554688, 791.1752319335938, 751.5667114257812, 702.6944580078125, 640.8783569335938, 560.1911010742188, 450.4346008300781, 292.44805908203125, 45.489723205566406]

dpm++,shift=7.0,step=20,timesteps: [999, 992, 984, 975, 965, 954, 942, 928, 913, 895, 874, 851, 823, 790, 749, 699, 636, 552, 437, 269]

dpm++,shift=11.0,step=20,timesteps: [999, 995, 989, 984, 977, 970, 962, 953, 942, 930, 916, 899, 879, 855, 824, 785, 733, 659, 549, 366]

Eulerのほうが安定するかもと前述したが875をちょうど通る設定をしやすいのは逆にdpm++の方である。

切り替えノード

ComfyUIには、Wan2.2のhigh/lowモデルをtimestep境界に従って自動切り替えするノードも存在するようです。

まとめ

Wan2.2ではT2Vで0.875、I2Vで0.900を境にhigh/low noiseモデルを切り替える。
この境界はflow shift関数とshift値から導出でき、shift=7なら前半と後半を1:1に分割される。
timestep=875を正確に通るかはサンプラー設定次第だが、厳密でなくても大きな問題は少ないと思われる。(というかtimestep=875前後で切り替えることすら意識してない人もいる)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?