AMDのWindowsマシンで動くAnythingV3.0 WebUIを更新(スケジューラと複数枚生成)

AMDのWindowsマシンで動くAnythingV3.0 WebUIを更新(スケジューラと複数枚生成)

グラボを換えてもDirectMLは死なず。
という事でやりかけになっていたWebUIをとりあえず形にしたのでここで供養します。

3090TiでもAMDの時のDirectML環境がそのまま動いたので多分使えます。

AMD WebUI スクリプト

前回記事はこちら

AMD環境のWindowsマシンで動くAnythingV3.0に自力で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-….”)は記事のバージョンではなく最新の物をおすすめします。

とうとうRyzen + RADEONのAMD環境にもWindowsで動くStable Diffusionがきた

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環境に嘆く人の最適解となるか。

 

コメントを残す