テキストから連想画像を生成するDALL-Eの再現モデルをGoogle ColabPro+で動かしてみた

##今回動かしたのは、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

###（ 関連 ）

なお、cedro3さんは、BIG GAN + CLIPでテキスト画像変換するモデルも実装されています。

http://cedro3.com/ai/biggan-clip/

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

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

##作成した動画

####__（ 入力テキスト ）__

__*"A naked beautiful Italian girl in the shape of silver iron sculpture with golden long hair blowing in the wind with standing on the blue marble stand."*__

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


####（ 入力テキスト ）

__*"My mother is cooking my favorite cake in the kitchen. I cannot help but watching her cook it."*__

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

####（ 入力テキスト ）

__*"Teddy bear in the shape of the pyramid having silver skin with 2 wooden green dog style legs."*__

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

##DALL-Eとは？

__DALL-E__は、__Image-GPT3__をベースとしています。__DALL-E__と__Image-GPT3__のアルゴリズムの内容については、次のサイトがわかりやすいです。

- [OpenAIのDALL-Eは言葉による指示で「それらしい」画像を作り出す](https://jp.techcrunch.com/2021/01/06/2021-01-05-openais-dall-e-creates-plausible-images-of-literally-anything-you-ask-it-to/)
- [文章から画像を生成するOpenAI 「DALL-E」について解説](https://data-analytics.fun/2021/02/05/openai-dalle-blog/)
- [OpenAIが画像生成用のGPT-3モデルを発表](https://www.infoq.com/jp/news/2021/04/openai-gpt-image/)

##実行環境

- Google Colab+ （定額月額 5,243円）
- GPU: Tesla V100
- Python: Python 3.7.11

###__Google Colaboratoryでの動かし方__

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

> ###3.コード
> コードはオリジナルを少しいじったものをGithubに上げてあります。自分で動かしてみたい方は、この__[「リンク」](https://github.com/cedro3/others/blob/master/DALL_E.ipynb)__をクリックし表示されたノートブックの先頭にある「Colab on Web」ボタンをクリックすると動かせます。

上の文の中で、「このリンク」と書かれている部分のリンク先のnotebookのコードを参考にしました。

###__（ 今回、下敷きとしてベースにしたGoogle Colaboratoryのnotebook ）__

https://github.com/cedro3/others/blob/master/DALL_E.ipynb

####__Google ColabPro+ コード__

ここに掲載したコードを上から順に、Google ColaboratoryやColabPro, ColabPro+にコピー＆ペーストして実行していくと、最終的に、入力した英文テキストにもとづく画像が生成されます。

生成された画像は、Google Driveのカレント・ディレクトリにpngファイルとして出力されます。

__*cedro3*__さんのサイトに掲載されているノートブックを一部改変しました。

- マウント先のGoogle Driveに、DALL-Eから吐き出される画像を保存するように変えた
- 英文テキストを引数として受け取ると、その英文の内容から連想される画像や、英文に記述された場面を描写した画像を出力するメソッドを作った

```Python3:GoogleColabPro+
# GPUスペック確認
!nvidia-smi -L
!pwd
```

####Google Driveをマウント

```Python3:GoogleColabPro+
from google.colab import drive
drive.mount('/content/drive')

%cd drive/MyDrive
!ls
```

####Google Drive内の作業ディレクトリに移動（任意のフォルダ）

- 以下は、Googleドライブのルート直下に、__dall-e_colab__というフォルダが作成済みである場合の移動さきです。
- 自分のGoogleドライブの中に作成した、任意の作業フォルダに移動してください。（__*cd*__以降は、適宜、作成した任意の作業フォルダの相対パスに置き換えてください）

```Python3:GoogleColabPro+
%cd dall-e_colab

!ls
```

####Open AIから公開されているCLIPを入れる（*git clone*）

```Python3:GoogleColabPro+
# CLIP関連コードのコピー
! git clone https://github.com/openai/CLIP.git
!ls

%cd CLIP
!pwd
```

####環境構築（*DALL-E*を含めて、必要なモジュールのインストール及び定数の宣言・値設定）

```Python3:GoogleColabPro+
# Pytorchバージョン変更
! pip install torch==1.7.1+cu110 torchvision==0.8.2+cu110 -f https://download.pytorch.org/whl/torch_stable.html 

# Pytorch画像処理ライブラリー・インストール
! pip install kornia==0.5.4


# 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')

import torch
import numpy as np
import torchvision
import torchvision.transforms.functional as TF
import torchvision.transforms as T
import kornia
import PIL
import os, io, sys
import random
import imageio
from IPython import display
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
from google.colab import output
import requests
```


```Python3:GoogleColabPro+
# 初期設定
im_shape = [512, 512, 3]
sideX, sideY, channels = im_shape
target_image_size = sideX
tau_value = 2.
```

####メソッド定義

```Python3:GoogleColabPro+
# 画像表示・保存
def displ(img):
  img = np.array(img)[:,:,:]
  img = np.transpose(img, (1, 2, 0))
  imageio.imwrite('output.png', np.array(img))
  return display.Image('output.png')

# 画像のランダム切り出し
def augment(out, cutn=16):
  p_s = []
  for ch in range(cutn):
    sizey = int(torch.zeros(1,).uniform_(.5, .99)*sideY)
    sizex = int(torch.zeros(1,).uniform_(.5, .99)*sideX)
    offsetx = torch.randint(0, sideX - sizex, ())
    offsety = torch.randint(0, sideY - sizey, ())
    apper = out[:, :, offsetx:offsetx + sizex, offsety:offsety + sizey]
    apper = apper + .1*torch.rand(1,1,1,1).cuda()*torch.randn_like(apper, requires_grad=True)
    apper = torch.nn.functional.interpolate(apper, (224,224), mode='bilinear')
    p_s.append(apper)
  into = augs(torch.cat(p_s, 0))
  return into

# 正規化と回転設定
nom = torchvision.transforms.Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711))
augs = kornia.augmentation.RandomRotation(30).cuda()

# パラメータの設定
class Pars(torch.nn.Module):
    def __init__(self):
        super(Pars, self).__init__()
        hots = torch.nn.functional.one_hot((torch.arange(0, 8192).to(torch.int64)), num_classes=8192)
        rng = torch.zeros(1, 64*64, 8192).uniform_()
        for i in range(64*64):
            rng[0,i] = hots[[np.random.randint(8191)]]
        rng = rng.permute(0, 2, 1)
        self.normu = torch.nn.Parameter(rng.cuda().view(1, 8192, 64*64))
        
    def forward(self):      
      normu = torch.nn.functional.gumbel_softmax(self.normu.reshape(1,64*64,8192), dim=1, tau=tau_value).view(1, 8192, 64, 64)
      return normu

```

##以下をメソッド化

ここから、オリジナルのColaboratory notebookではベタ打ちで実行していたコードを、繰り返し実行しやすいようにメソッドのブロックに包みます。

- メソッド名： *draw_image_based_upon_text*
- 引数： *text* （取り扱う英文テキスト。*str*型オブジェクト）

####__（ 改変前のオリジナル ）__

https://github.com/cedro3/others/blob/master/DALL_E.ipynb

####__（ 改変後のメソッド定義 ）__

```Python3:GoogleColabPro+
def draw_image_based_upon_text(text):
  # テキスト入力
  text_input = text

  # テキストを特徴ベクトルに変換
  token = clip.tokenize(text_input)  
  text_v = model.encode_text(token.cuda()).detach().clone()
  # パラメータリセット
  latent = Pars().cuda()  
  param = [latent.normu]  
  optimizer = torch.optim.Adam([{'params': param, 'lr': .01}]) 

  # images フォルダーリセット
  import os
  import shutil
  if os.path.isdir('images'):
     shutil.rmtree('images')
  os.makedirs('images', exist_ok=True)

  # 学習ループ
  for iteration in range(1001):

    # --- 順伝播 ---
    # パラメータから画像を生成
    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()  

    # 逆伝播
    optimizer.zero_grad()
    loss.backward()
    optimizer.step() 

    # 学習率の調整
    for g in optimizer.param_groups:
      g['lr'] = g['lr']*1.005
      g['lr'] = min(g['lr'], .12)

    # ログ表示      
    if iteration % 50 == 0:
      with torch.no_grad():
        
        # 生成画像の表示・保存
        out = unmap_pixels(torch.sigmoid(dec(latent())[:, :3]).float())  
        displ(out.cpu()[0])  
        shutil.copy('output.png', './images/%s.png'%str(int(iteration/50)).zfill(6))

        # データ表示
        print('iter = ',iteration)
        for g in optimizer.param_groups:
          print('lr = ', g['lr'])
        print('tau_value = ', tau_value)
        print('loss = ',loss.item())
        print('\n')

```

####引数となるテキスト（*str*型のインスタンス）を定義して、メソッドを実行

- 引数：*'an armchair in the shape of an avocado'*

```Python3:GoogleColabPro+
# テキスト入力
text_input = 'an armchair in the shape of an avocado'
```

- メソッド実行

```Python3:GoogleColabPro+
draw_image_based_upon_text(text_input)
```

####画像ファイルがどんどん吐き出される（画像ファイルを確認）

- カレント・ディレクトリの直下に__*images*__というディレクトリが作られます。
- すでに同名のディレクトリがある場合は、ディレクトリごと削除されて、新しいディレクトリが作られる。
- __*images*__ディレクトリの直下に、引数に渡した英文をもとに*DALL-E*が生成した画像（拡張子ong）が、どんどん吐き出される。

![](https://user-images.githubusercontent.com/87643752/131114651-fa8af68c-d47d-4ad4-b50d-50226e9b8fb4.png)

- 生成される画像は、時間が経つにつれて解像度があがり、画面内の各オブジェクトも時間が経つにつれて少しずつ描画されていく。
- メソッド内でベタ打ちした*iteration*数が終わると、画像の生成が止まる。

```Python3:GoogleColabPro+
!ls
!ls images

from IPython.display import Image
Image("./images/000000.png")
```

![](https://user-images.githubusercontent.com/87643752/131023596-2adfe092-29c2-40c4-aed1-7e4743ff4ee3.png)

```Python3:GoogleColabPro+
Image("./images/000019.png")
```

![](https://user-images.githubusercontent.com/87643752/131023919-0b8ff2f0-cf3a-43ab-92e5-808cb4a49c28.png)


####生成された画像を、パラパラ漫画の動画にする

__オリジナルのnotebookから、最初の次のコードを削除しました。__

>```Python3:
>#images フォルダーの最後の画像を5枚コピー
> import shutil
> for i in range(21,26,1):
>     shutil.copy('output.png', './images/%s.png'%str(int(i)).zfill(6))
>```


```Python3:GoogleColabPro+
# ouput.mp4を一旦削除
import os 
if os.path.exists('./output.mp4'):
   os.remove('./output.mp4')

# images フォルダーの画像から動画を生成
! ffmpeg -r 5 -i images/%06d.png -vcodec libx264 -pix_fmt yuv420p output.mp4
```

- MP4が出力された確認


```Python3:GoogleColabPro+
!ls | grep mp4
```


```Python3:GoogleColabPro+
output.mp4
```

![](https://user-images.githubusercontent.com/87643752/131120257-522dddf8-c940-4d4d-9380-a1b30ac920fb.png)

####__MacbookのiMovieを使って、タイトルとBGMを入れた短編ムービー__

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

####*iteration*数を第2引数に加えたメソッドを作る

- メソッド名： *draw_image_based_upon_text*
- 引数１： *text* （取り扱う英文テキスト。*str*型オブジェクト）
- 引数2： *iteration_num* （*iteration*数。*int*型オブジェクト）

```Python3:GoogleColabPro+
def draw_image_based_upon_text(text, iteration_num):
  # テキスト入力
  text_input = text
  iteration_number = iteration_num

  # テキストを特徴ベクトルに変換
  token = clip.tokenize(text_input)  
  text_v = model.encode_text(token.cuda()).detach().clone()
  # パラメータリセット
  latent = Pars().cuda()  
  param = [latent.normu]  
  optimizer = torch.optim.Adam([{'params': param, 'lr': .01}]) 

  # images フォルダーリセット
  import os
  import shutil
  if os.path.isdir('images'):
     shutil.rmtree('images')
  os.makedirs('images', exist_ok=True)

  # 学習ループ
  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()  

    # 逆伝播
    optimizer.zero_grad()
    loss.backward()
    optimizer.step() 

    # 学習率の調整
    for g in optimizer.param_groups:
      g['lr'] = g['lr']*1.005
      g['lr'] = min(g['lr'], .12)

    # ログ表示      
    if iteration % 50 == 0:
      with torch.no_grad():
        
        # 生成画像の表示・保存
        out = unmap_pixels(torch.sigmoid(dec(latent())[:, :3]).float())  
        displ(out.cpu()[0])  
        shutil.copy('output.png', './images/%s.png'%str(int(iteration/50)).zfill(6))

        # データ表示
        print('iter = ',iteration)
        for g in optimizer.param_groups:
          print('lr = ', g['lr'])
        print('tau_value = ', tau_value)
        print('loss = ',loss.item())
        print('\n')

```

####メソッド実行

- __*images*__ディレクりの名前を変える（消されないようにするため）


```Python3:GoogleColabPro+
!mv images images_old

!ls images_old | wc -l
!ls images_old | head
!ls images_old | tail
```

- 入力する英文：*'Sir.Winston Churchill shakes hands with Stalin at the Disneyland Resort in California.'*
- *iteration*数を$10000$にして実行

```Python3:GoogleColabPro+
# テキスト入力
text_input = 'Sir.Winston Churchill shakes hands with Stalin at the Disneyland Resort in California.'

draw_image_based_upon_text(text_input, 10000)
```

####画像ファイルがどんどん吐き出される（画像ファイルを確認）

```Python3:GoogleColabPro+
!ls images | wc -l
!ls images | tail

from IPython.display import Image
Image("./images/000199.png")
```

![](https://user-images.githubusercontent.com/87643752/131024192-3faf0af8-72a7-40d8-8bc3-2023fab39e9a.png)


##多くの深層学習モデルと同様に、実行する度に異なる結果が出る

```Python3:GoogleColabPro+
draw_image_based_upon_text(text_input, 10000)
Image("./images/000199.png")
```

![](https://user-images.githubusercontent.com/87643752/131024780-98a7360c-0851-43df-bb9c-f3d93006652a.png)

```Python3:GoogleColabPro+
!mv images images_old2
!ls
```

##その他、定義したメソッドを使って、さまざまな英文テキストをもとに画像を生成させる


- 引数1：*"Teddy bear in the shape of the pyramid having silver skin with 2 wooden green dog style legs."*
- 引数2: $10000$


```Python3:GoogleColabPro+
input_text = "Teddy bear in the shape of the pyramid having silver skin with 2 wooden green dog style legs."

draw_image_based_upon_text(input_text, 10000)
!ls images | tail

Image("./images/000199.png")
```

![](https://user-images.githubusercontent.com/87643752/131024843-1ff669c7-a6ea-407e-93fd-1872b92c2bad.png)


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

```Python3:GoogleColabPro+
!mv images images_old4
```


```Python3:GoogleColabPro+
input_text = "Young boy and girl are enjoying their first kiss inside the man's ｒecreational vehicle with opened big window opend."

draw_image_based_upon_text(input_text, 10000)

!ls images | tail
Image("./images/000199.png")
```

![](https://user-images.githubusercontent.com/87643752/131024902-1d2be556-865f-4d2b-8cf7-70c6e1d2a40e.png)

##多くの深層学習モデルと同様に、実行する度に異なる結果が出る

```Python3:GoogleColabPro+
draw_image_based_upon_text(text_input, 10000)
Image("./images/000199.png")
```

![](https://user-images.githubusercontent.com/87643752/131024970-dc9cabd1-f1ec-4acc-997e-060b1f7b9de5.png)


```Python3:GoogleColabPro+
mv images images_old5
```


```Python3:GoogleColabPro+
input_text = "A chef fries a black tiger shrimp with black pepper with delicious sound."

draw_image_based_upon_text(input_text, 10000)
```

![](https://user-images.githubusercontent.com/87643752/131025392-422fc032-213d-459f-bad6-403c79a654ae.png)

```Python3:GoogleColabPro+
mv images images_old6
```


```Python3:GoogleColabPro+
input_text = "My mother is cooking my favorite cake in the kitchen. I cannot help but watching her cook it."

draw_image_based_upon_text(input_text, 10000)
!ls images | tail
Image("./images/000199.png")
```

![](https://user-images.githubusercontent.com/87643752/131025574-63de1d5a-ebee-406d-b20d-324b91a3599c.png)

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


- 引数1：*"A naked beautiful Italian girl in the shape of silver iron sculpture with golden long hair blowing in the wind with standing on the blue marble stand."*
- 引数2: $10000$


```Python3:GoogleColabPro+
input_text = "A naked beautiful Italian girl in the shape of silver iron sculpture with golden long hair blowing in the wind with standing on the blue marble stand."

draw_image_based_upon_text(input_text, 10000)
!ls images | tail

Image("./images/000199.png")
```

![](https://user-images.githubusercontent.com/87643752/131144756-874d0e34-fe5b-48cd-b511-c88ceb796b53.png)

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

#参考

###【 コード例 】

カレント・ディレクトリ直下のimages_old4ディレクトリにある画像ファイル群を、動画にするとき

- カレント・ディレクトリに__*output_4.mp4*__という動画ファイルが出力される

```Python3:GoogleColabPro+
# ouput.mp4を一旦削除
import os 
if os.path.exists('./output_4.mp4'):
   os.remove('./output_4.mp4')

# images フォルダーの画像から動画を生成
! ffmpeg -r 5 -i images_old4/%06d.png -vcodec libx264 -pix_fmt yuv420p output_4.mp4
```

カレント・ディレクトリにある画像ファイル群を、動画にするとき

- カレント・ディレクトリに__*output_new.mp4*__という動画ファイルが出力される

```Python3:GoogleColabPro+
# ouput.mp4を一旦削除
import os 
if os.path.exists('./output_new.mp4'):
   os.remove('./output_new.mp4')

# images フォルダーの画像から動画を生成
! ffmpeg -r 5 -i ./%06d.png -vcodec libx264 -pix_fmt yuv420p output_new.mp4
```

##動画の数秒間に背景黒のテロップ・フレームを入れる場合

- DALL-Eから吐き出される画像ファイルのファイル名を、"000020.png"から開始される連番にする

```Python3:GoogleColabPro+
# 出力画像ファイル名を000020.pngから開始する連番にする
def draw_image_based_upon_text(text, iteration_num):
  # テキスト入力
  text_input = text
  iteration_number = iteration_num

  # テキストを特徴ベクトルに変換
  token = clip.tokenize(text_input)  
  text_v = model.encode_text(token.cuda()).detach().clone()
  # パラメータリセット
  latent = Pars().cuda()  
  param = [latent.normu]  
  optimizer = torch.optim.Adam([{'params': param, 'lr': .01}]) 

  # images フォルダーリセット
  import os
  import shutil
  if os.path.isdir('images'):
     shutil.rmtree('images')
  os.makedirs('images', exist_ok=True)

  # 学習ループ
  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()  

    # 逆伝播
    optimizer.zero_grad()
    loss.backward()
    optimizer.step() 

    # 学習率の調整
    for g in optimizer.param_groups:
      g['lr'] = g['lr']*1.005
      g['lr'] = min(g['lr'], .12)

    # ログ表示      
    if iteration % 50 == 0:
      with torch.no_grad():

        # 生成画像の表示・保存
        out = unmap_pixels(torch.sigmoid(dec(latent())[:, :3]).float())  
        displ(out.cpu()[0])  
        shutil.copy('output.png', './images/%s.png'%str(int(iteration/50)+20).zfill(6))

        # データ表示
        print('iter = ',iteration)
        for g in optimizer.param_groups:
          print('lr = ', g['lr'])
        print('tau_value = ', tau_value)
        print('loss = ',loss.item())
        print('\n')

```

- 次に、吐き出されるファイルと縦横サイズが同じ背景黒の画像ファイルを、"000000.png"〜"000019.png"まで出力する

```Python3:GoogleColabPro+
import cv2

#画像を読み込む
frame = cv2.imread('./images/000020.png')

#サイズ、チャンネルを読み込む
h,w,c = frame.shape

height = h
width = w

#背景黒の画像を作成
#（参考）https://peaceandhilightandpython.hatenablog.com/entry/2017/08/14/153635
# uint8で0埋めの配列を作る。
# 幅16、高さ24のサイズ
# zeros(shape, type) shapeは配列の大きさ
# 配列の（行数、列数）になっている
# 画像はwidth,heightの慣習があるが、ココは逆なので気をつけること
imageArray = np.zeros((height, width, 3), np.uint8)

for i in range(0, 20):
	file_name = "./images/" + str(str(i).zfill(6)) + ".png"
	cv2.imwrite(file_name, imageArray)

```

- 動画ファイルを生成

```Python3:GoogleColabPro+
# ouput.mp4を一旦削除
import os 
if os.path.exists('./output.mp4'):
   os.remove('./output.mp4')

# images フォルダーの画像から動画を生成
! ffmpeg -r 5 -i images/%06d.png -vcodec libx264 -pix_fmt yuv420p output.mp4
```

- あとは、iMovieやAdobe Premiere & Adobe After Effectsなどで、最初の20フレームの黒画像にタイトルやキャプションをつける

####（例）

```Python3:GoogleColabPro+
input_text = "A nuclear submarine launched an ICBM missile from the sea toward Russia."
draw_image_based_upon_text(input_text, 5000)
```

```Python3:GoogleColabPro+
!ls images | head -30
```

```Python3:GoogleColabPro+
000020.png
000021.png
000022.png
000023.png
000024.png
000025.png
000026.png
000027.png
000028.png
000029.png
000030.png
000031.png
000032.png
000033.png
000034.png
000035.png
000036.png
000037.png
000038.png
000039.png
000040.png
000041.png
000042.png
000043.png
000044.png
000045.png
000046.png
000047.png
000048.png
000049.png
```

```Python3:GoogleColabPro+
!ls images | tail
```

```Python3:GoogleColabPro+
000110.png
000111.png
000112.png
000113.png
000114.png
000115.png
000116.png
000117.png
000118.png
000119.png
```

```Python3:GoogleColabPro+
import cv2

#画像を読み込む
frame = cv2.imread('./images/000020.png')

#サイズ、チャンネルを読み込む
h,w,c = frame.shape

height = h
width = w

#背景黒の画像を作成
#（参考）https://peaceandhilightandpython.hatenablog.com/entry/2017/08/14/153635
# uint8で0埋めの配列を作る。
# 幅16、高さ24のサイズ
# zeros(shape, type) shapeは配列の大きさ
# 配列の（行数、列数）になっている
# 画像はwidth,heightの慣習があるが、ココは逆なので気をつけること
imageArray = np.zeros((height, width, 3), np.uint8)

for i in range(0, 20):
    file_name = "./images/" + str(str(i).zfill(6)) + ".png"
    cv2.imwrite(file_name, imageArray)
```

- メソッド化する

```Python3:GoogleColabPro+
def insert_head_20_black_frames():
  import cv2

  #画像を読み込む
  frame = cv2.imread('./images/000020.png')

  #サイズ、チャンネルを読み込む
  h,w,c = frame.shape
  height = h
  width = w

  #背景黒の画像を作成
  #（参考）https://peaceandhilightandpython.hatenablog.com/entry/2017/08/14/153635
  # uint8で0埋めの配列を作る。
  # 幅16、高さ24のサイズ
  # zeros(shape, type) shapeは配列の大きさ
  # 配列の（行数、列数）になっている
  # 画像はwidth,heightの慣習があるが、ココは逆なので気をつけること
  imageArray = np.zeros((height, width, 3), np.uint8)

  for i in range(0, 20):
    file_name = "./images/" + str(str(i).zfill(6)) + ".png"
    cv2.imwrite(file_name, imageArray)

```

- メソッドを実行する

```Python3:GoogleColabPro+
insert_head_20_black_frames()
```

```Python3:GoogleColabPro+
!ls images | head -30
```

```Python3:GoogleColabPro+
000000.png
000001.png
000002.png
000003.png
000004.png
000005.png
000006.png
000007.png
000008.png
000009.png
000010.png
000011.png
000012.png
000013.png
000014.png
000015.png
000016.png
000017.png
000018.png
000019.png
000020.png
000021.png
000022.png
000023.png
000024.png
000025.png
000026.png
000027.png
000028.png
000029.png
```

```Python3:GoogleColabPro+
!ls images | tail
```

```Python3:GoogleColabPro+
000110.png
000111.png
000112.png
000113.png
000114.png
000115.png
000116.png
000117.png
000118.png
000119.png
```

![](https://user-images.githubusercontent.com/87643752/131215236-35d8944e-9e52-4f0e-b055-118c5fcaa4f7.png)

![](https://user-images.githubusercontent.com/87643752/131215238-358d24e0-8c49-4a12-bf59-452d7d5fbaf8.png)

```Python3:GoogleColabPro+
# ouput.mp4を一旦削除
import os 
if os.path.exists('./output.mp4'):
   os.remove('./output.mp4')

# images フォルダーの画像から動画を生成
! ffmpeg -r 5 -i images/%06d.png -vcodec libx264 -pix_fmt yuv420p output.mp4
```