テキスト文から連想される絵を自動描画するDALL-Eの再現モデルに、"水の中で燃え盛る炎のイメージ”と語りかけたら、美しい色遣いの絵が誕生した件

###DALL-Eが描いた絵 （イテレーション数：7,000 @ NVIDIA P100 GPU)

<iframe width="560" height="315" src="https://www.youtube.com/embed/wIDjaexRSKw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

以下の記事の続編です。

####__（ 少し前に書いた記事 ）__

https://qiita.com/electronics_diy721/items/ca38096c74cfe1c53e30

作成した__*draw_image_based_upon_text*__メソッドを使って、指示文として与えた英文から画像を生成してみます。


```Python3:
input_text = "a image of flame in the water"
draw_image_based_upon_text(input_text, 7000)
```

![](https://user-images.githubusercontent.com/87643752/131873689-1b2ebd82-430e-47aa-9986-a4711515fb0f.png)

##今回動かしたのは、DALL-Eの再現モデル

### 【 再現モデルの構成 】 「DALL-EのDiscrete VAE + CLIP」の連携モデル

__DALL-E__の実装コードについて簡単に触れさせてください。
__DALL-E__は、Open AIによって開発・発表されましたが、実装コードは一部しか公開されていません（2021年9月5日現在）。

公開されているのは、画像データの次元数を圧縮して、データサイズが小さい画像特徴ベクトルを作り出す部分だけです（この画像次元数を圧縮する部分は、__*Discrete VAE*（離散変分オートエンコーダ）__という手法が採用されています）。

####（ DALL-E実装コードの公開部分 ）

https://github.com/openai/DALL-E

> ###Overview
>
>This is the official PyTorch package for the discrete VAE used for DALL·E. The transformer used to generate the images from the text is not part of this code release.
>
> ###Installation
>Before running the example notebook, you will need to install the package using
>
>```bash:
>pip install DALL-E 
>```

DALL-Eの中で、テキスト文を入力値として受け取り、受け取った文に描かれている場面・情景や概念をうまく表現するイメージ画像を、出力値として出す部分は、未公開の状況です（2021年9月5日現在）。

OpenAIの公式GitHubに掲げられている次の文でそのことが述べられています。

> The transformer used to generate the images from the text is not part of this code release.

実装コードが公開されていないこの部分は、120億個のパラメータを持つTransformerモデルです。Open AIは、ウェブ空間から、　2億5千万件の画像とテキストのペアを集めて、このTransformerモデルを学習させたと発表しています。

残念ながら、テキストを画像に変換する肝心の部分が未公開のため、Open AIから公開されている実装コードだけでは、DALL-Eモデルを動かすことはできません。

ところで、Open AIからは、テキストと画像の類似度を数値で評価してくれる__CLIP__モデルも公開されています。
__CLIP__に画像ファイルを１枚と、任意個の英単語を引数として渡して実行すると、その画像が任意個ある各英単語に対応する確率を小数（確率値）で返してくれます。全単語の小数（確率値）の総和をとると１になります。

例えば、ドラえもんの画像ファイルと、単語リスト ["dog", "cat", "human", "melon", "ice cream", "car"]を渡して、返り値として[0.200, 0.700, 0.035, 0.025, 0.015, 0.025]が得られたとしましょう。

この例では、画像が"cat"に該当する確率値が"0.700" (=70%）ともっとも高いので、ドラえもんの画像は、指定した単語リストの中では、"cat"である確率が最も高いとCLIPが判断したことになります（"cat"の次に該当確率が高い単語ラベルは、"dog"になる。"dog"の該当確率は0.200 (=20%)です）。

この__CLIP__に、次の２つのベクトルを入力データとして入れることで、テキストと画像が__どれだけ似ているか__の__正解率を得る__ことができます。

- 【 入力１ 】　 ユーザから入力されたテキスト文を特徴ベクトルに変換した文ベクトル
- 【 入力２ 】　 低次元の画像ベクトル。DALL-Eの構成部品としてすでに公開されている画像データの次元圧縮器（*Discrete VAE*）から出力された画像ベクトル

この__CLIPから出力され正解率（類似度）__を、__誤差逆伝播で最大化する__ことで、__与えられたテキスト文に対応する適切な画像を「生成」する__ことができます。

この「公開済みのDALL-Eの画像圧縮器」と、「（DALL-Eを開発したOpenAIから別に公開されている）__CLIP__」を連結させた__DALL-Eの再現モデル__のコード実装が、サードパーティのプログラマである[@advadnoun氏](https://twitter.com/advadnoun)によって公開されています。そして、この実装コードにさらに改良の手を加えたコードが、__*cedro3*__さんによって公開されています。（このコードをこの記事では、「擬似DALL-Eモデル」と呼ぶことにしたのでした）。

http://cedro3.com/ai/dall-e/

__擬似DALL-Eモデル__は、英文指示文を受け取って、その文に描かれた内容を描写した画像を自動生成するとき（＝推論フェーズ）、次のループ処理を指定されたイテレーション（iteration）回数、繰り返します。

####（ 以下のループをひたすら回す ）

・Discrete VAEにランダムパラメータを与えて、 画像を生成
・テキストと、DALL-E Image Decoderから出力された画像をそれぞれ、clipで特徴ベクトル化
・両ベクトル間の類似度をclipで算出（clipで画像とテキストの類似度評価）
・類似度をさらに高めるために、 ランダムパラメータを更新
・新たなランダムパラメータをDiscrete VAEに入力し、 前回よりもテキストに近い画像を生成

```Python3:GoogleColaboratory
# CLIPのモデル化
! pip install ftfy regex
import clip
model, preprocess = clip.load('ViT-B/32', jit=True)  
model = model.eval()  

# DALL-Eのモデル化
! pip install DALL-E
from dall_e import map_pixels, unmap_pixels, load_model
dec = load_model("https://cdn.openai.com/dall-e/decoder.pkl", 'cuda')

  （ 中略 ）

# テキスト入力
text_input = text
iteration_number = iteration_num

# テキストを特徴ベクトルに変換
token = clip.tokenize(text_input)  
text_v = model.encode_text(token.cuda()).detach().clone()
  
 （ 中略 ）
  
# 学習ループ
for iteration in range(iteration_number):
   # --- 順伝播 ---
   # パラメータから画像を生成
   out = unmap_pixels(torch.sigmoid(dec(latent())[:, :3].float()))
   # 画像をランダム切り出し・回転  
   into = augment(out)
   # 画像を正規化
   into = nom((into))
   # 画像から特徴ベクトルを取得
   image_v = model.encode_image(into)
   # テキストと画像の特徴ベクトルのCOS類似度を計算 
   loss = -torch.cosine_similarity(text_v, image_v).mean() 
```

今回は、この__*cedro3*__さんの実装コードをGoogle Colab+で動かしました。
なお、次のウェブサイトでも、この「DALL-Eのdiscrete VAE + CLIP」の組み合わせが採用されています。

https://axross-recipe.com/recipes/148