Stable Diffusionは内部でCLIPと呼ばれるモデルを使用しています。CLIPを使うと何ができるようになるのかを見てみましょう。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
前回はStable Diffusionでノイズから画像が生成される過程を確認しました。今回は少し方向性を変えて、CLIP(Contrastive Language-Image Pre-Training)と呼ばれ、Stable Diffusionの内部でも使われている「テキストとイメージ(画像)の組を基に学習を行ったモデル」について見てみます。
今回もコードはGoogle Colabのノートブックとして公開することにしました(かわさき)。
CLIPは、OpenAIという組織が2021年1月5日に「DALL・E: テキストから画像を生成」と同時に発表した技術で、AIエンジニアやデータサイエンティストの間では有名ですね。OpenAI公式ページでは「CLIP: テキストと画像をつなぐ」というタイトルの記事が公開されています(一色)。
Stable Diffusion(をラップしたDiffusersのStableDiffusionPipelineクラス)では、CLIP(CLIP ViT-L/14)を利用してプロンプトを「埋め込み表現」と呼ばれる「単語や文の意味をn次元空間に埋め込んだベクトル」に変換し、それを潜在表現(latent representation)と一緒に画像生成用のモデル(U-Net)へと入力するようになっています。
txt2img.pyファイルのコードと等価な処理かどうかは、両方のコードの見た目がずいぶんと異なっているのでちょっと確認できていません。ざっくりと見分けるのであれば、同じ設定でtxt2img.pyファイルとStableDiffusionPipelineクラスに画像を生成させて、その結果を確認するという方法があるかもしれませんね。
まずCLIPでどんなことができるのかを簡単に確認してみましょう。なお、ここではベクトルのコサイン類似度を簡単に確認できるsentence_transformersが提供しているclip-ViT-L-14モデルを使用することにします。これを利用して生成される埋め込み表現が、StableDiffusionPipelineクラスで実際に生成される埋め込み表現と異なる可能性があることには注意してください。それでも、CLIPにどんなことができるのかは十分に理解できるはずです。
今回もGoogle Colabのノートブックを使っているので、以下のように先頭に「!」付けて「pip install transformers scipy ftfy diffusers sentence_transformers」コマンドを実行しておきましょう。
次にCLIP ViT-L/14モデル(これは恐らく「Vision Transformerを使用した巨大サイズのCLIP、パッチレベル14」という意味です)を利用したモデルをインスタンス生成します。
from sentence_transformers import SentenceTransformer, util
model = SentenceTransformer('clip-ViT-L-14')
なお、 先頭行ではutilモジュールをインポートしていますが、このモジュールにはコサイン類似度を計算するcos_sim関数が含まれています。
モデルを生成したら、さっそく簡単な単語から埋め込み表現を作ってみましょう。
dog = 'a dog'
dog_emb = model.encode(dog)
print(dog_emb)
print(dog_emb.shape)
埋め込み表現を作成するにはモデルのencodeメソッドに文字列(テキスト、プロンプト)を渡すだけです。ここでは「a dog」という2語を渡しています。最後の2行では返された埋め込み表現とそのサイズを表示しています。
数多くの浮動小数点数値が表示され、768次元(1行768列)であることが分かりました。
「Stable Diffusion with Diffusers」で示されている以下の図を覚えている方がいれば、上の形状(1行768列)がStable Diffusionが内部で使用している埋め込み表現とは異なっていることに気付くかもしれませんね。
この動作原理ではプロンプトからは77行768列の埋め込み表現が作られることになっています。しかし、ここではCLIPによりどんなことができるのかを見るだけなので、このまま話を続けることにしましょう。
ここで作成した埋め込み表現は、「a dog」というテキストがどのような意味を持つかが768次元空間のいずれかの座標にマッピングすることで表現されているものと考えられます。また、これと似た意味を持つテキストは768次元空間の中で近い位置に存在します。それがどのくらい似ているかを示すのが先ほども出てきた「コサイン類似度」です。
コサイン類似度は2つのベクトル(ここでは768次元ベクトル)がどれくらい似ているかを示すもので「1に近いほど2つのベクトルはよく似ていて、0に近いほど2つのベクトルは無関係であり、-1に近いほど2つのベクトルはよく似ていない」といったことがいえます。
というわけで、犬の「反対」っぽい猫(a cat)の埋め込み表現を作って、2つの埋め込み表現がどのくらい似ていないか(または似ているか)を確認してみましょう。
cat = 'a cat'
cat_emb = model.encode(cat)
後はこれをutilモジュールのcos_sim関数に渡すだけでコサイン類似度を計算できます。
similarity = util.cos_sim(dog_emb, cat_emb)
print(similarity)
結果はどんなものでしょうか。
何と「a dog」と「a cat」のコサイン類似度は「0.9177」になりました。先ほどもいいましたが、コサイン類似度は1に近いほど、2つのベクトルが似ていることを意味します。CLIPは単に「犬←→猫」という概念だけではなく、哺乳類であるとか、生物であるとか、そんなことまでを768次元空間の中で表せるようになっているのかもしれません。そうなると、無関係なもの、あるいは全く似ていないものを考えつくのもなかなか難しいものです。
Copyright© Digital Advantage Corp. All Rights Reserved.