グラボを換えてもDirectMLは死なず。
という事でやりかけになっていたWebUIをとりあえず形にしたのでここで供養します。
3090TiでもAMDの時のDirectML環境がそのまま動いたので多分使えます。
AMD WebUI スクリプト
前回記事はこちら
機能アップを重ねて第6版まできました(gr_6.py)
import gradio as gr import datetime import random from diffusers import StableDiffusionOnnxPipeline, DDIMScheduler, PNDMScheduler import numpy as np def generate(prompt, nega_prom, Sched, gennum, height, width, steps, cfg, tagseed): #Schedulerの選択 if Sched == "DDIM" : print("Scheduler:DDIM") ScheSet = DDIMScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", num_train_timesteps=1000, clip_sample=False, set_alpha_to_one=False) elif Sched == "PNDM" : print("Scheduler:PNDM") ScheSet = PNDMScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", num_train_timesteps=1000) else : print("Scheduler:default") ScheSet = Sched #パイプラインの設定 if ScheSet == "Default" : pipe = StableDiffusionOnnxPipeline.from_pretrained("./anything-v3.0",provider="DmlExecutionProvider") else : pipe = StableDiffusionOnnxPipeline.from_pretrained("./anything-v3.0",provider="DmlExecutionProvider",scheduler=ScheSet) pipe.safety_checker = lambda images, **kwargs: (images, [False] * len(images)) loop = gennum while loop > 0: #シード値の生成 if tagseed == "": seed = int(random.randrange(4294967294)) else: seed = int(tagseed) tagseed = ""; print(f"Seed value : {seed}") latents = get_latents_from_seed(seed, width, height) #イメージ生成と保存 gen_img = pipe(prompt=prompt, negative_prompt=nega_prom, height=height, width=width, num_inference_steps=steps, guidance_scale=cfg, latents=latents).images[0] gen_img.save(f"./outputs/any3_{Sched}_step{steps}-cfg{cfg}-{seed}.png") loop = loop - 1 return gen_img #Latentsの生成 def get_latents_from_seed(seed: int, width: int, height:int) -> np.ndarray: # 1 is batch size latents_shape = (1, 4, height // 8, width // 8) # Gotta use numpy instead of torch, because torch's randn() doesn't support DML rng = np.random.default_rng(seed) image_latents = rng.standard_normal(latents_shape).astype(np.float32) return image_latents #UIの定義 webui = gr.Interface(fn=generate, inputs=[ gr.Textbox(label = 'Prompt text', value="", lines=2, elem_id="prompt"), gr.Textbox(label = 'Negative Prompt text', value="", lines=2, elem_id="nega_prom"), gr.Radio(["Default","DDIM","PNDM"], value="Default", label = 'Sched', elem_id="Scheduler"), gr.Slider(label = 'Loop count', minimum=1, maximum=20, step=1, value=1, elem_id="gennum"), gr.Slider(minimum=64, maximum=1024, step=64, label="縦サイズ(px)", value=768, elem_id="height"), gr.Slider(minimum=64, maximum=1024, step=64, label="横サイズ(px)", value=512, elem_id="width"), gr.Slider(minimum=10, maximum=150, step=1, label="ステップ数", value=25, elem_id="steps"), gr.Slider(minimum=1, maximum=10, step=0.5, label='CFG', value=7.5, elem_id="cfg"), gr.Textbox(label = 'seed', value=None, placeholder="0 - 4294967294. Blank is random.", elem_id="tagseed"), ], outputs=gr.Image().style(height=768) ) webui.launch()
使い方
基本的な環境作成
前回同様、以下の記事を「学習データのダウンロードとOnnxへの変換」まで進めてください。
途中でダウンロードするonnxruntime(”ort_nightly_directml-….”)は記事のバージョンではなく最新の物をおすすめします。
DL&変換のためのスクリプトを準備したら、アニメ特化のAnything Ver3.0をダウンロード&変換します。
python convert_stable_diffusion_checkpoint_to_onnx.py --model_path="Linaqruf/anything-v3.0" --output_path="anything-v3.0"
diffuserのバージョンを0.5.1まで上げます(後述)。
pip install diffusers==0.5.1
2つのファイルを修正します。
まず\virtualenv\Lib\site-packages\diffusers\schedulers\scheduling_ddim.pyの264行目を修正。
変更前)pred_original_sample = (sample - beta_prod_t ** (0.5) * model_output) / alpha_prod_t ** (0.5) 変更後)pred_original_sample = (torch.FloatTensor(sample) - beta_prod_t ** (0.5) * torch.FloatTensor(model_output)) / alpha_prod_t ** (0.5)
次に\virtualenv\Lib\site-packages\diffusers\pipelines\stable_diffusion\pipeline_stable_diffusion_onnx.pyの169行目
変更前)sample=latent_model_input, timestep=np.array([t]), encoder_hidden_states=text_embeddings 変更後)sample=latent_model_input, timestep=np.array([t], dtype=np.int64), encoder_hidden_states=text_embeddings
これでWebUIを起動してください。
python gr_6.py
なお実行時に”scipy”,”accelerator”のモジュールを求められたらpip installで追加してください(未確認)。
以下は調査記録というか、自分の知識の袋小路メモです。
奇特な方だけどうぞ。
追加機能1.スケジューラ追加
できるかぎり新しいDiffuserを
StableDiffusion=お絵かきAIで「何ができる、何ができない」というのは大きくdiffuserのバージョンに依存します。
例えばダメ要素を指定するNegative PromptはDiffuser 0.4.0の新機能でした。
よって当初参照した記事の通り0.3.0のままだと、今となっては古い(といっても数ヶ月前)機能しか使えません。
そこでどこまでdiffuserを最新にできるかを試しました。
結果、改造無しで上げられるのはdiffuser Ver.0.5.1まで。
これ以上はテンソルがなんだ、VAEがなんだと言われ自分には解決できませんでした。
使えるスケジューラの選別
ともかく0.5.1にする事で使えるスケジューラ(サンプラー)の幅が少し広がりました。
“.\Lib\site-packages\diffusers\__init__.py”を見る限り、
v0.5.1にて使えるスケジューラは以下の通り(Flex…は除く)。
- DDIMScheduler
- DDPMScheduler
- KarrasVeScheduler
- PNDMScheduler
- SchedulerMixin
- ScoreSdeVeScheduler
このそのまま動いたのは”DDIMScheduler”と”PNDMScheduler”のみ。
これに無指定の際にデフォルトで仕様されるスケジューラ(名称不明)の合計3つが自分の動かせたスケジューラです。
KarrasVeSchedulerについては実際にGenerateさせようとすると
File "C:\temp\virtualenv\lib\site-packages\diffusers\pipelines\stable_diffusion\pipeline_stable_diffusion_onnx.py", line 180, in __call__ latents = self.scheduler.step(noise_pred, t, latents, **extra_step_kwargs).prev_sample TypeError: KarrasVeScheduler.step() missing 1 required positional argument: 'sample_hat'
DDPMSchedulerについては
File "C:\temp\virtualenv\lib\site-packages\diffusers\pipelines\stable_diffusion\pipeline_stable_diffusion_onnx.py", line 151, in __call__ latents = latents * self.scheduler.init_noise_sigma TypeError: unsupported operand type(s) for *: 'numpy.ndarray' and 'Tensor'
というエラーで止まります。
解決方法が分かる人いたら教えてください。
SchedulerMixinとScoreSdeVeSchedulerについては別の用途らしくわかりませんでした。
variance exploding stochastic differential equation (VE-SDE) scheduler
The variance exploding stochastic differential equation (SDE) scheduler.
For more information, see the original paper: https://arxiv.org/abs/2011.13456
スクリプト補足
無指定(標準)+DDIM+PNDMの3つにしぼり、選択式のラジオボタンを設定しました。
#Schedulerの選択
無指定以外はScheSetにパラメータを入れ、パイプラインに渡します。
変数はHugging FaceのSchedulersを参照。
#パイプラインの設定
無指定の場合のみ、パイプラインにscheduler=が書いてあるとエラーになりました。
よってifで回避しています。
pipe.safety_checkerはsfwチェックを無効化するもの。
スケジューラによる作画の違い
Anything V3.0モデルから。
Promt:cool woman waring dress, wind,solo,multicolor
NetativePromt:lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry,mecha,nsfw,looking at viewer,breast,loli
Step:25
CFG:7.5
Seed値:1528346647
Default
DDIM
PNDM
DDIMが一番細部のディティールを描き分けられています。
麦わらの端や服のシワ、髪の毛の揺れ具合など。
左手の表現はDefaultの方が崩れが少ないですが場合によりそう。
PNDMはDefaultに近いですが、左手が崩れてしまっています。
次いでStableDiffusion V1.5モデル。
Promt:Aerial Shoot of skyscraper stand on solitary on a lagoon island, Emerald green sea, Dubai, The vast ocean, highly detailed, 8k, ultra-wide shot, sunny, art by greg rutkowski
NetativePromt:Distorted
Step:30
CFG:6
Seed値:3096771901
Default
DDIM
PNDM
題材の問題なのか、Anythingほどスケジューラによる差は生まれませんでした。
特にDefaultとPNDMは差を見つけるのが難しいほど。Stepを75まで上げたら肉眼での差はわかりませんでした。2つは非常に似たスケジューラなのかもしれません。
DDIMは霞ががる遠景の空気感も書き分けられているとも言えます。
追加機能2.複数枚生成
UIをどうするとか面倒だったので、./outputフォルダに指定枚数を吐き出すだけのシンプルな実装にしました。
どうせWindowsなら無理にブラウザ内で見るより、フォルダ開いてフォトアプリとかで開いたほうが早いし。
生成枚数はスライダーを使い最大20枚まで指定できます。
シード値を指定した場合、最初の1枚だけを指定値で生成。あとはランダムシードになります。
WebUIにプレビューされる画像は最後に生成された画像なのでご注意下さい。
とまあ・・・作りは適当だけど目的は達した感。
コレでようやくAMDのグラボでもシードガチャしやすくなったと思います。
OnnxDiffusersUIを紹介します
2023/01/23追記
先日知ってしまいました。
「自分のやりたいことをさらに数段上のレベルで実現してる」RADEON Windows向けWebUIのようです。
この手で動作検証ができないので”書いてある通りならそう”くらいですが。
中身はOnnxなので、自分と全く同じ環境構築が必要。
checkpoint形式からOnnx形式へのモデル変換をするのも一緒。
ただしDiffusersのバージョン制限解除、それによる7つのスケジューラ。
複数枚生成時のGrid、img2img/inpaintingのUIなどを実現されていて素晴らしい。
RADEON環境に嘆く人の最適解となるか。