• 2022-09-30
  • サイボウズラボ機械学習勉強会
  • 仕組みの話
    • 使い方とかビジネス上の価値とかの話はしない
  • 目的: 「ブラックボックスを減らす」
    • 最初「ブラックボックスをなくす」と書いていたが、ブラックボックスがなくなるまで深さ優先探索で掘っていったら10時間経っても終わらないので幅優先探索にする

Stable Diffusionの仕組み

  • ざっくり全体像
  • image
  • 3つの主用部品がある
  • 拡散モデル (Denoising Diffusion Probabilistic Models, DDPM)
    • 基本的には「ノイズを取り除く仕組み」を繰り返し使うことで画像を生成する
    • ネットから集めた画像xとそれにノイズを加えたものyを用意して「yを入力したらxが出るニューラルネット」を学習させる
    • これを純粋なノイズに対して適用すると新しい画像が生まれる
    • image
      • 実際にStable Diffusionの処理中の値を抜き出して可視化した
      • 左端が純粋なノイズ、ノイズ除去を繰り返して猫になってる
    • image
  • High-Resolution Image Synthesis with Latent Diffusion Models
    • latent diffusion model
      • このlatentの意味
      • 画像自体の空間ではなく、VAEで低次元な空間(latent space)にエンコードしてから拡散モデルをしてデコードする
        • VAEの話はまた今度
      • Stable Diffusionの標準的な設定だと4×64×64次元のテンソル
      • image
        • 最後にこのVAE decodeで512×512のRGB画像に戻してる
      • 空間が80万次元(3×512×512)から2万次元(4×64×64)に縮んだことで学習が効率的になった
  • [Denoising Diffusion Implicit Models]
    • Denoiseのプロセスが10〜100倍高速になった
    • かつてのモデルでは1ステップずつDenoiseしていた
      • これを陰解法を使って複数ステップまとめて行なう
      • 「処理Xを20回行った結果」を許容可能な精度で推測Yできるなら、処理Xを20回やるのではなく処理Yをしたらいいよね、という発想
    • 実際、Stable Diffusionの標準的な設定だと1000ステップのノイズ除去処理を、20ステップずつ塊にして50回で行なっている
      • image ここまでで質問
  • Q: Stableって何を意味してる?
    • A: 単なるネーミング、DreamBoothのDreamって何と言ってるようなもの、ただのプロジェクト名
    • Q: ノイズを除去するとか全然安定しそうにない
    • A: なんでこのネーミングにしたのかは僕は作者ではないのでわからない
    • B: 安定してきれいな絵が出ますよという雰囲気で名付けたのかな
  • Q: プロンプトとは
    • A: 入力する文字列のこと、詳しくは次で説明します
      • 世の中的にはテキストを入れて絵が出てくるツールだと認識されてるけど、ここまでの説明ではまだテキストを入れるところが説明されてない
    • Q: デノイズの処理自体はプロンプト関係ないってこと?
    • A: プロンプト関係ないというか…
      • 拡散モデルの画像生成の仕組みとしてはただのノイズからデノイズをして画像を作るというもの
      • このデノイズの部分を条件付き確率にして条件指定でいじれるようにしてあって、そこのところに条件としてプロンプト文字列を入れることができるようにしている、という仕組み
      • 追記: この条件パラメータは別にテキストである必要などなく、実際に論文では色々な種類の条件を入れる実験をしている
        • 世の中的に「テキストプロンプトを入れるだけで絵が出る!」という経路が知識のない人でも使えてバズっただけのこと
  • Q: テンソルの4×64×64の4は、4枚あるということ?
    • A: 4枚あるということ。4チャンネルあると捉えてもいい
    • Q: 3×512×512の3は?
    • A: RGBの3チャンネル
  • Q: 1000ステップを1回にまとめてやらずに20ステップずつ50回やるのはなぜ?
    • たくさんまとめてやればやるほど「ちゃんと1ステップずつやった時とのズレ」が大きくなる
    • 数式的には1000ステップを1回でやる更新式も作れるけど、これは推定なので誤差も大きくなる
    • 誤差が大きくなりすぎると実用上のメリットがなくなる
      • 時間と精度のトレードオフで、20回くらいだとまあまあ実用的ということ

プロンプト

  • 画像を生成する時に入力するテキストのこと
  • サブワードに分割された上で、1トークン(多くの場合1単語)が768次元のベクトルになる
    • bozumanのような辞書にない単語を入れると1単語が3トークンに分割されたりする
    • プロンプトをトークンに分割したタイミングで77個を超える時は切り捨てて固定長にしてる
      • 短い場合は0でパディング
  • 77トークン×768次元のテンソルになる
    • image
    • これは[CLIP]がやる
      • Stable Diffusionでは学習していない
        • 既存の公開されてるモデルを取ってきて変更しないで部品として使ってるだけ
      • ざっくりいえば画像と文章の対応づけ(どの画像とどの文章がペアかを当てる)タスクの学習
        • 5つ画像があって5つテキストがあって、どれとどれがペアでしょう?みたいなやつ
      • 画像も文章も768次元のベクトルに射影されてコサイン類似度を計算できる
      • 大規模に学習されてモデルが公開されているのでいろんなプロジェクトが部分部分で活用している
        • Stable Diffusionではプロンプトの埋め込みにだけ使われている
  • Denoiseの時にプロンプトの情報を注意機構で見に行く
    • 注意機構が具体的にどんなサイズなのか
    • ノイズ除去のプロセスは具体的にはU-Netになってて、各層から注意機構が伸びてるんで全体を説明するのは大変だから、一箇所取り出して解説する
    • image
      • プロンプトは768次元のベクトルが77個ある
      • それを適当なニューラルネットでそれぞれ300次元に変換したものがある
        • これがキーの集合Kとバリューの集合V
      • どっかから取ってきた情報を300次元に変換したもの、これがクエリーQ
      • QとKをmatmulする、要するにそれぞれのベクトルに対して内積とることに相当する
      • で、それをSoftmaxに入れるとベクトルの方向が近いところの値が大きくなる
        • これがアテンションウェイト
        • 仮にどこか1箇所が1になったとするなら次のVとのmatmulは実質的に「その一つを選択する」に相当する
        • つまり「77トークンのどれに注目して、どれを無視するか」がこの値に込められている
      • こうやって注目するところだけ混ぜ合わせたバリューを作っている
      • この仕組み自体はいわゆる「注意機構」であって、ありふれたもの、StableDiffusion特有のことは何もしていない
    • U-Net model for Denoising Diffusion Probabilistic Models (DDPM)
      • https://nn.labml.ai/diffusion/ddpm/unet.html
      • image
      • U-Netは簡単にいえば画像を入力として画像を出力する系のタスクに使われる部班
        • 一旦低解像度高チャンネル数の表現を通す仕組み
        • その細い空間を通す前の情報をコピーして貼り付けている
          • 灰色の矢印と白い四角
          • 低解像度の空間を通した情報と通してない情報の両方を使って高解像度の情報を再現する
          • この貼り合わせるところで注意機構からの情報も追加していると僕は理解している、間違ってるかもしれない
      • 上記の図では572×572の33万次元の情報が一旦28×28の小さな画像になってる
        • 1024チャンネルもあるので80万次元に増えてる
          • 画像の広い範囲から集めた抽象度の高い情報が、この深いチャンネルのところに詰め込まれているのだろう
        • 高次元の情報の処理で一旦低次元空間を通すってのはオートエンコーダなどとも関連した概念で、それによって認識などに必要ではない「瑣末な情報」を捨てることができる
          • 次元減ってなかった
          • 空間方向の解像度を下げることで瑣末な高周波成分を捨てるなどと言われてる
          • 途中の次元が減ってないのでオートエンコーダ的に元画像の復元タスクをやらせると完璧に復元してしまう
          • 図のネットワークはセグメンテーションのタスクを例に説明されている
          • そういうタスクなら画像の1ピクセル1ピクセルがバラバラにあっても解けない問題だからたくさんのチャンネルが有効に使われるのかな
          • セグメントは物理的な局在している
            • 画面上に散らばったセグメントなどはない
            • =画素の高周波成分が影響しにくい
            • こういう人間の認知のパターンにフィットした結果を出すために、低解像度化して空間周波数方向の成分を捨てている
  • guidance_scale
    • パラメータ一覧にこれがあって「なんだろうな?」と思った人が多そう
    • guidance_scale is defined analog to the guidance weight w of equation (2) of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf

    • image
    • プロンプトがない時のノイズの推定(unconditional noise prediction) と、ある時のノイズの推定をそれぞれ計算する
    • その差に係数をかけて足し合わせる、つまりどれくらいプロンプトを重視するかをこのパラメータで決める
    • 式の形から0〜1にするのかと思いきやデフォルト値は7.5
      • 実際の推定よりもプロンプトの影響を強調して適用している
    • NovelAIではこの第二項のunconditional noise predictionが、ネガティブプロンプトのconditional noise predictionに置き換わってる。
      • それによってネガティブプロンプトの効果は通常のプロンプトと逆向きになる

Stable Diffusionのシードとプロンプトの関係

  • これは未踏ジュニア向けに説明した記事、一旦このページに移って説明する

Stable Diffusion埋め込みテンソル編集

  • image
  • プロンプト(テキスト)を入れて画像を生成する仕組みだと世の中的には認識されてるが、プロンプトは即座にベクトル空間に埋め込まれるので加算やスカラー倍ができる

img2imgの仕組み

  • image
    • 前回text to imageをした時は、初期値は単なる乱数だった
      • この方法では人間が与えた画像を潜在空間に埋め込んでから、それにちょっとノイズを加えて初期値にする
      • 元画像に例えば75%くらいのノイズをかけて、それから75%の回数のDenoiseをする
        • ノイズの強さとDenoiseの回数は両方strengthで決まる
        • ノイズが少なければ元の画像に近いものになる
        • ノイズを大きくすればより大きく変わる
        • この解説の絵のパラメータは下記
  • strengthを変えて試してみた結果
    • strengthを0.6から0.99まで0.01刻みで増やした
    • image
      • 画像の「step: 0.1」は「step: 0.01」のtypo
    • ノイズの量が多いほど元の絵を無視してフリーダムに描く
      • 左上では僕が書いたものとだいぶ近い
      • 右下では猫がいなくなったり椰子の木が猫になったり猫が砂に埋められたりフリーダムなことになってる
    • Q: プロンプトはどうなってる?
      • A: 全部共通でprompt: “cat, sea, wave, palm tree, in Edvard Munch style”
        • Edvard Munchってのは「ムンクの『叫び』」のムンクです
        • 空の塗り方にムンクみが出てますね
        • 僕が最初に与えた画像は単色でぺったり塗っていたので左上の方ではそれが再現されてるけど、右下に行くほど空の塗りが複雑になっていく
    • この実験の時に失敗したなーと思うのは、ノイズを乗せる時のランダムシードを固定してないところ
      • 結果のバリエーションが広いのはそのせい
      • 固定して実験した方がその要素を無視できて良かったかもね
    • 右下とか99%ノイズなわけなので、手前が砂で奥が海という構図を維持できてるのがむしろ驚き
    • 0.6台の猫部分の拡大
      • image imageimageimage
      • 僕が適当に描いたのは「それ猫か?」という耳の形状なのだが、まともな耳の形に修正されている、よい
  • 手書きの図をいれてどうなるか実験
    • 手書きの図をきれいに清書してくれると嬉しい
    • が、今のところ良いプロンプトを見つけてない
      • image image

      • 9割ノイズを入れて描き直してるのだけど差がわかりにくい

      • image image

      • image image

      • この辺がきれいになってるのだけどw

        • 細かすぎてわかる人の方が少ないw
      • そして逆に文字などが別の文字に化けてる(5がSになったり)

        • image
    • 手書き風の画像が出てきてる
    • パスドローなどできっちり真っ直ぐな線や円弧で仕上げた図表が出るといいなぁ
      • そういうのを出すプロンプトが見つかるといいのだけど…
      • ファインチューニングでそういうスタイルを学習させる手もある

inpaint

  • image
  • image
  • 「マスクしてないところだけを描き直してくれる機能」ではない
    • それは一般人向けの雑な説明
    • 「マスクされてるところは一切変更しないで、残りの部分だけを境界の辻褄が合うように作る」って仕組みではない
    • 僕も最初はそうだと思い込んでいたが、理解に反する挙動があって詳しく調べたら違うとわかった
      • image
        • マスク領域が維持されてないように見えるけど何がいけないのか??(2022/9/12)

        • 神様部分をマスクしている。上下の余白はマスク外。
          • image
        • 神様は元絵のママになり余白には適当に絵が描かれることを期待したがそうはならなかった。
        • Q: マスク部分が変わるの驚き
          • A: ですよね、神様部分がめちゃくちゃ書き変わって「僕の使い方とかコードとかがおかしいのかな?」と悩みました
    • 仕組みがわかると当たり前
      • 間で一旦潜在空間を通るので元の画像を維持できるだけの情報量がない
    • 一見マスク部分が維持されてるように見えるベンチ犬のサンプルも、拡大してみるとマスクされたベンチの網目模様が変化しているのがわかる
      • image
      • たまたま人間がベンチの模様には注目していないので気付きにくいだけ
      • 人間の注意が中央の犬と猫に誘導されている
    • 現実的なワークフローは生成後に改めて合成
  • 詳しい仕組み説明してなかった
    • image
    • マスク画像の白い部分は「自由に描いて良い」
      • 黒い部分は「自由に書いて良いが適当な係数で元画像とブレンドするよ」
      • デノイズの過程で何度も元画像とブレンドされる
        • なので最終的に黒い部分は「元画像にまあまあ近い」になる
        • この処理はもちろん潜在空間で行なっているので「潜在空間で近い」にすぎない、64x64の解像度
          • 64×64の画像を512×512にVAEで戻した画像は、元画像に一致しはしない
          • 猫と神様の例では、この「戻した画像」が人間の許容できるクオリティにならなかった
          • なぜならフェンスの柵と違って神様は「前景」であり「人間が注目するところ」だったから

img2promptの仕組み

  • methexis-inc/img2prompt – Run with an API on Replicate
  • image
    • 今まで話していたStable Diffusionのtxt2img はテキストから画像を作る仕組み
    • Stable Diffusionとは別のプロジェクトとして、画像を入力してそれを説明するタスクがある
      • これを少しいじって「Stable Diffusionに入れると良さそうなプロンプトを作る」をやっているプロジェクト、リポジトリがある
    • この例では、黄色い目の黒猫、色鉛筆画で、なんとかさんの書いた絵っぽい
      • ついでに細々とした属性、チョークで描いた絵だとか炭で描いた風だとか、あと謎にCC-BYのライセンスまでつけてきたんだけどw
  • まずはBLIPで画像説明を作る
    • a painting of a black cat with yellow eyesの部分がそれ
    • ざっくり仕組み
      • 画像を分割してそれぞれの部分を説明し、それをまとめる
      • 全体としてみたら黒猫だし、拡大してみると黄色い目、という感じで説明文が生成されている
      • 他には「窓枠の上にいる猫」とか「猫が並んでる」など
    • なので僕は「black cat」としか指示してないのに、僕が指示した以上のデティール解説が出てきている
      • 目が黄色くなったのは乱数シードの影響です
  • その後で、付け加える要素を候補から総当たりで探索してる
    • 例えば作家名リストには5219人の名前が書かれている
      • Edvard MunchとかWassily Kandinskyとか、他に思いつかないけど色々書かれてる
      • ここから総当たりで探索する
        • くっつけて類似度が一番増えたものを採用していく
      • 知らない画家や画風キーワードを発見する機会になる
    • CLIPのところで書いたコサイン類似度
      • 画像も文章も768次元のベクトルに射影されてコサイン類似度を計算できる

    • 目的画像に近くなったかどうかをコサイン類似度で見て、近くなるキーワードを発見して組み合わせる仕組み
      • 注: この768次元は、たまたま次元が一致してるけどトークンの埋め込み空間とは別物
        • もう1段階先の「テキストと画像が同じ768次元空間に埋め込まれる」の空間
  • BLIPだけでコサイン類似度0.2くらい出る
    • 2次元のイメージでいると「全然似てないやん」となるが、このコサイン類似度は768次元空間で計算されている
    • 高次元においてコサイン類似度0.2は激レア
    • 768次元なので100万分の1以下
    • 追加の探索によって0.22~0.24になる
  • 注意点
    • CLIPの768次元ベクトルの空間での類似度を高める探索を行っている
    • 「そのプロンプトを入れた時にその絵が出力される尤度」を高めているわけではない
      • そこは全然別物、それをやるのはむしろ次で説明するTextual Inversion

Textual Inversion

  • Textual Inversionを試してみる
    • image
  • 5枚程度の画像Aを食わせて1時間待つと768次元のベクトルBが出てくる仕組み
  • このベクトルはプロンプトのトークン埋め込みと同じ空間
    • catとkittenの補間とかをやってた空間
  • これを*などの普段使わないトークンに割り当てて、以降のプロンプトで使えるようにする
  • 詳しい学習方法は掘り下げてないが、ざっくりいえば「Bに埋め込まれる1単語をプロンプトにして画像生成した時にAと似た特徴の画像が生成される確率が高くなるように学習」
  • 当初は猫の柄やボウズマンのデザインが再現されることを期待したのだが、期待過剰だったのでは
    • そもそも768次元のベクトル1個が出てくるだけ
      • ボウズマンの柄みたいな「それを表現するコンパクトな語彙」が存在しないものを1単語相当のベクトルで表現するのは無茶
    • 人類が言語で区別しているがユーザがその区別で表現できてない時には有用
    • たとえば「こんな感じの猫」を「cat」という曖昧な概念でしか表現できてないユーザ
    • AIを擬人的に説明(メタファー):
    • AI「これはorange catっぼいな」
      • image
    • AI「でもtabbyではない」
      • image
    • AI「bicolor的なんだけど色が違うな」
      • image
    • AI「orange bicolor!そうそうこんな感じ」
      • image
    • AI「これは違う、yellow eyesではなくgreen eyesだ」
      • image
    • 擬人化しているので言語的な思考に例えたが、実際にはこういう言語的な思考をするのではなく、ベクトルを変えて「近くなったかどうか」を判断する
    • 768次元しかない「1単語の意味の空間」を通る関係上、サイボウズのロゴのような画像的記憶を学習させることができない
    • 猫の柄に対する語彙と、ボウズマン的なものの柄に対する語彙では前者の方が充実している
      • なので前者の方がやりやすい
  • 昨日DreamBoothが使いやすい形でリリースされた
    • @psuraj28: dreambooth#stablediffusion training is now available in 🧨diffusers!

    • And guess what! You can run this on a 16GB colab in less than 15 mins!

    • image

    • VRAM16GB、15分でファインチューニングできる
    • Textual Inversionと原理が違って顔のデザインが維持されてる?
    • 今後試してみたいところ

Q: Stable Diffusion埋め込みテンソル編集で、単語のベクトルを足し合わせても連続的に変わらないのは、アテンションする場所が深いところにあるから連続的に変わらない?

  • A: ガサっと変わるところはノイズから画像にしていくプロセスの序盤に近いところで分岐していると思う
    • イメージを口頭で伝えるのは難しいな
    • image
      • 基本的にはプロンプトのベクトルがほとんど変わらないので、入力が同じなら出力もほとんど同じであるはず
      • ところがそれが分水嶺を跨いだときは、差が拡大して、その結果入力値が離れているのでさらに差が拡大して…という現象が起きる
  • Q: 注意機構の意味でのアテンションが大きく変わるところで絵が大きく変わるのかと思った
  • A: この実験に関していうとプロンプトの形は同一でcatの1単語のベクトルだけを滑らかに変更しているから、アテンションが急激に変わって、それがこの振る舞いに出ている、というわけではないのではないかと思う
    • アテンションの可視化はまだできていないから断言はできない
    • (補足: Stable Diffusionにおいてアテンションは、色々変えられはするけどデフォルトでは「プロンプトのトークン77個に対するアテンション」なことに注意、画像のどこに注目するか、的なことはしていない)
    • catとkittenの間を補間しているとはいえ、どっちも名詞なのだから構文上の大きな変化はないはずで、アテンションは大きく変わってないのでは
  • B: デノイズを50回繰り返す過程で途中で分岐して、そこから結果が大きく変わって、最終的に出てくるものが非連続であるように見えるということだと思う
  • A: そう、写像自体が線形ではないので、それを何回も重ねた結果を見ると当然非連続な振る舞いをするところはあるよね、そりゃそうだろうな、という感じの雰囲気です
  • Q: それはバタフライ効果みたいな話ですか?
  • A: バタフライ効果みたいな話です
    • 補足追記:
      • 差が拡大する写像を何度も重ね掛けしていると初期値のごく僅かな差が結果の大きな差につながりうるという話、東京で蝶が羽ばたいた影響でアメリカにハリケーンがくる、という例え
      • 今回のケースでは正確に言えば、初期値は完全に同一で、写像がごくわずかに違う。この場合でも同様に誤差拡大が発生することはあるだろう、たぶんそれが起こってるのだろう、という話
    • プロンプトの影響が小さかったとしても、それによって山の右側に落ちるのか左側に落ちるのかが変われば、その後のデノイズでは離れる方向に動いていくわけです
      • image
        • 流れが山にぶつかって分岐するイメージ
      • Q: なるほど、それでそれぞれの道でそれっぽくなるように発展していくと
      • A: そう、それぞれの道でより良くなるように進んだ結果、入力は差がなかったとしても出力が大きく離れたものにたどり着く、それは非線形なので大いにありうること

Q: word2vecみたいにベクトルの足し算引き算ができるのが面白い

  • A: やってみないとわからないね、僕はできるだろうと思っていたが、思った以上に非連続なジャンプが多いなという印象
    • 一応inpaintのマスクで顔の部分だけ消して「catっていったけどここはもっとkitten寄りで」みたいに指示を出して描き直させることは技術的にはできる
    • だけども制御効きにくいものに対してそういう細かい操作をしようとするよりランダムシードで100個出してそこから選ぶ方が人間の負担が少ないと思う