グラボを換えても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環境に嘆く人の最適解となるか。










