ホーム » Deep Dream

Deep Dream」カテゴリーアーカイブ

TensorFlow 2.0 : 上級 Tutorials : 生成 :- DeepDream

TensorFlow 2.0 : 上級 Tutorials : 生成 :- DeepDream (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 11/21/2019

* 本ページは、TensorFlow org サイトの TF 2.0 – Advanced Tutorials – Generative の以下のページを翻訳した上で
適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

無料セミナー開催中 クラスキャット主催 人工知能 & ビジネス Web セミナー

人工知能とビジネスをテーマにウェビナー (WEB セミナー) を定期的に開催しています。スケジュールは弊社 公式 Web サイト でご確認頂けます。
  • お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
  • Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。

お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。

株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/
Facebook: https://www.facebook.com/ClassCatJP/

 

生成 :- DeepDream

このチュートリアルは、Alexander Mordvintsev の ブログ投稿 で説明されている、DeepDream の最小限の実装を含みます。

DeepDream はニューラルネットワークにより学習されたパターンを可視化する実験です。子供が雲を見てランダムな形状を解釈しようとするときと同様に、DeepDream はそれが画像で見るパターンを過剰解釈 (= over-interpret) して強化します (= enhance)。

それはネットワークを通して画像を forward してから、特定の層の活性に関して画像の勾配を計算することによりそれを行ないます。それから画像はこれらの活性を増加するために変更されて、ネットワークにより見られたパターンを強化して、そして夢のような画像という結果になります。このプロセスは “Inceptionism” として呼称されました (InceptionNet と、映画 Inception への参照です)。

ニューラルネットワーク “dream” をどのように作成してそれが画像で見たシュールなパターンを強化できるかを実演しましょう。

from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
import numpy as np

import matplotlib as mpl

from IPython.display import clear_output
from matplotlib import pyplot as plt
from tensorflow.keras.preprocessing import image

 

夢にする (= dream-ify) 画像を選択する

このチュートリアルのために、ラブラドール の画像を使用しましょう。

url = 'https://storage.googleapis.com/download.tensorflow.org/example_images/YellowLabradorLooking_new.jpg'
# Download an image and read it into a NumPy array.
def download(url, target_size=None):
  name = url.split('/')[-1]
  image_path = tf.keras.utils.get_file(name, origin=url)
  img = tf.keras.preprocessing.image.load_img(image_path, target_size=target_size)
  return img

# Normalize an image
def deprocess(img):
  img = 255*(img + 1.0)/2.0
  return tf.cast(img, tf.uint8)


# Display an image
def show(img):
  plt.figure(figsize=(12,12))
  plt.grid(False)
  plt.axis('off')
  plt.imshow(img)
  plt.show()

# Downsizing the image makes it easier to work with.
original_img = download(url, target_size=[225, 375])
original_img = np.array(original_img)

show(original_img)
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/YellowLabradorLooking_new.jpg
90112/83281 [================================] - 0s 0us/step

 

特徴抽出モデル

事前訓練された画像分類モデルをダウンロードして準備します。InceptionV3 を使用します、これは DeepDream で元々使用されたモデルに類似しています。任意の 事前訓練されたモデル は動作しますが、けれども下で層の名前を (これを変更している場合) 調整しなければならないことに注意してください。

base_model = tf.keras.applications.InceptionV3(include_top=False, weights='imagenet')
Downloading data from https://github.com/fchollet/deep-learning-models/releases/download/v0.5/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5
87916544/87910968 [==============================] - 6s 0us/step

DeepDream のアイデアは層 (or 層群) を選択して画像が層を「励起する」ような方法で「損失」を段々と最大化することです。組み入れられる特徴の複雑さは貴方により選択された層に依拠します、i.e., より低い層はストローク (短い線) や単純なパターンを生成する一方で、より深い層は画像の洗練された特徴、あるいはオブジェクト全体でさえも与えます。

InceptionV3 アーキテクチャは非常に巨大です (モデル・アーキテクチャのグラフについては TensorFlow の 研究 repo を見てください)。DeepDream については、関心のある層は畳み込みが結合されてるところのものです。InceptionV3 では 11 のこれらの層があります、’mixed0′ から ‘mixed10’ と名前付けられています。異なる層の使用は異なる夢のような画像という結果になります。より深い層は (目や顔のような) 高位な特徴に対応する一方で、早い層は (エッジ、形状とテクスチャーのような) 単純な特徴に対応します。下で選択された層で自由に実験してください、しかしより深い層はその上で訓練するためにより長い時間かかることに留意してください、何故ならば勾配計算がより深いためです。

# Maximize the activations of these layers
names = ['mixed3', 'mixed5']
layers = [base_model.get_layer(name).output for name in names]

# Create the feature extraction model
dream_model = tf.keras.Model(inputs=base_model.input, outputs=layers)

 

損失を計算する

損失は選択された層の活性の総計です。損失は各層で正規化されますので、より巨大な層からの寄与がより小さい層より重いということはありません。通常は、損失は勾配降下を通して最小化することを望む量です。DeepDream では、損失を勾配上昇を通して最大化します。

def calc_loss(img, model):
  # Pass forward the image through the model to retrieve the activations.
  # Converts the image into a batch of size 1.
  img_batch = tf.expand_dims(img, axis=0)
  layer_activations = model(img_batch)

  losses = []
  for act in layer_activations:
    loss = tf.math.reduce_mean(act)
    losses.append(loss)

  return  tf.reduce_sum(losses)

 

勾配上昇 (= gradient = ascent)

ひとたび選択された層のための損失を計算すれば、残されたことの総ては画像に関する勾配を計算してそれらを元の画像に追加することです。

勾配を画像に追加することはネットワークにより見られたパターンを強化します。各ステップで、ネットワークの特定の層の活性を段々と励起する画像を作成します。

@tf.function
def deepdream(model, img, step_size):
    with tf.GradientTape() as tape:
      # This needs gradients relative to `img`
      # `GradientTape` only watches `tf.Variable`s by default
      tape.watch(img)
      loss = calc_loss(img, model)

    # Calculate the gradient of the loss with respect to the pixels of the input image.
    gradients = tape.gradient(loss, img)

    # Normalize the gradients.
    gradients /= tf.math.reduce_std(gradients) + 1e-8 
    
    # In gradient ascent, the "loss" is maximized so that the input image increasingly "excites" the layers.
    # You can update the image by directly adding the gradients (because they're the same shape!)
    img = img + gradients*step_size
    img = tf.clip_by_value(img, -1, 1)

    return loss, img
def run_deep_dream_simple(model, img, steps=100, step_size=0.01):
  # Convert from uint8 to the range expected by the model.
  img = tf.keras.applications.inception_v3.preprocess_input(img)

  for step in range(steps):
    loss, img = deepdream(model, img, step_size)
    
    if step % 100 == 0:
      clear_output(wait=True)
      show(deprocess(img))
      print ("Step {}, loss {}".format(step, loss))


  result = deprocess(img)
  clear_output(wait=True)
  show(result)

  return result
dream_img = run_deep_dream_simple(model=dream_model, img=original_img, 
                                  steps=800, step_size=0.001)

 

それをオクターブ引き上げる (= Taking it up an octave)

悪くはないですが、この最初の試みでは 2, 3 の問題点があります :

  1. 出力は noisy です (これは tf.image.total_variation 損失で対処されるでしょう)。
  2. 画像は低解像度です。
  3. パターンはそれらは総て同じ細かさ (= granularity) で起きているようです。

これら総ての問題に対処する一つのアプローチは勾配上昇を異なるスケールで適用することです。これはより小さいスケールで生成されたパターンがより高いスケールのパターンに組み込まれるて追加の詳細で満たされることを可能にします。

これを行なうために前の勾配上昇アプローチを遂行してから画像のサイズを増やし (これはオクターブとして参照されます)、そしてこのプロセスを複数のオクターブのために繰り返すことができます。

OCTAVE_SCALE = 1.3

img = tf.constant(np.array(original_img))
base_shape = tf.cast(tf.shape(img)[:-1], tf.float32)

for n in range(3):
  new_shape = tf.cast(base_shape*(OCTAVE_SCALE**n), tf.int32)

  img = tf.image.resize(img, new_shape).numpy()

  img = run_deep_dream_simple(model=dream_model, img=img, steps=200, step_size=0.001)

clear_output(wait=True)
show(img)

 

タイルでスケールアップする

考えるべき一つのことは画像がサイズ的に増加するために、勾配計算を遂行するために必要な時間とメモリです。上のオクターブ実装は非常に巨大な画像や多くのオクターブ上では動作しません。この問題を回避するために画像をタイルに分割して各タイルのための勾配を計算することができます。

各 tiled された計算の前に画像にランダムシフトを適用することはタイルの継ぎ目が現れることを防ぎます。

ランダムシフトを実装することから始めます :

def random_roll(img, maxroll):
  # Randomly shift the image to avoid tiled boundaries.
  shift = tf.random.uniform(shape=[2], minval=-maxroll, maxval=maxroll, dtype=tf.int32)
  shift_down, shift_right = shift[0],shift[1] 
  img_rolled = tf.roll(tf.roll(img, shift_right, axis=1), shift_down, axis=0)
  return shift_down, shift_right, img_rolled
shift_down, shift_right, img_rolled = random_roll(np.array(original_img), 512)
show(img_rolled)

ここに先に定義された deepdream 関数の tiled された同値があります :

@tf.function
def get_tiled_gradients(model, img, tile_size=512):
  shift_down, shift_right, img_rolled = random_roll(img, tile_size)

  # Initialize the image gradients to zero.
  gradients = tf.zeros_like(img_rolled)

  for x in tf.range(0, img_rolled.shape[0], tile_size):
    for y in tf.range(0, img_rolled.shape[1], tile_size):
      # Calculate the gradients for this tile.
      with tf.GradientTape() as tape:
        # This needs gradients relative to `img_rolled`.
        # `GradientTape` only watches `tf.Variable`s by default.
        tape.watch(img_rolled)

        # Extract a tile out of the image.
        img_tile = img_rolled[x:x+tile_size, y:y+tile_size]
        loss = calc_loss(img_tile, model)

      # Update the image gradients for this tile.
      gradients = gradients + tape.gradient(loss, img_rolled)

  # Undo the random shift applied to the image and its gradients.
  gradients = tf.roll(tf.roll(gradients, -shift_right, axis=1), -shift_down, axis=0)

  # Normalize the gradients.
  gradients /= tf.math.reduce_std(gradients) + 1e-8 

  return gradients 

これをまとめるとスケーラブルで、octave-aware な deepdream 実装を与えます :

def run_deep_dream_with_octaves(model, img, steps_per_octave=100, step_size=0.01, 
                                num_octaves=3, octave_scale=1.3):
  img = tf.keras.preprocessing.image.img_to_array(img)
  img = tf.keras.applications.inception_v3.preprocess_input(img)

  for octave in range(num_octaves):
    # Scale the image based on the octave
    if octave>0:
      new_size = tf.cast(tf.convert_to_tensor(img.shape[:2]), tf.float32)*octave_scale
      img = tf.image.resize(img, tf.cast(new_size, tf.int32))

    for step in range(steps_per_octave):
      gradients = get_tiled_gradients(model, img)
      img = img + gradients*step_size
      img = tf.clip_by_value(img, -1, 1)

      if step % 10 == 0:
        clear_output(wait=True)
        show(deprocess(img))
        print ("Octave {}, Step {}".format(octave, step))
    
  clear_output(wait=True)
  result = deprocess(img)
  show(result)

  return result
dream_img = run_deep_dream_with_octaves(model=dream_model, img=original_img, step_size=0.01)

clear_output()
show(original_img)
show(dream_img)

遥かに良いです!貴方の DeepDream-ed 画像がどのように見えるかを変更するためにオクターブの数、オクターブ・スケールそして活性化された層で遊んでください。

読者はまた TensorFlow Lucid に興味があるかもしれません、これはニューラルネットワークを可視化して解釈するためにこのチュートリアルで紹介されたアイデアを拡張します。

 

以上






TensorFlow GoogLeNet Deep Dream の解析

TensorFlow GoogLeNet Deep Dream の解析

人工知能が見る悪夢、Deep Dream については TensorFlow で Deep Dream 入門 で Caffe 実装と TensorFlow 実装の Deep Dream をそれぞれ試してみました。

今回は TensorFlow 実装の Deep Dream を視覚的に解析してみます。
やりたい事は単純で、各層の重みをベースにノイズを乗せた画像が変形される様子を観察します。
モデルは、TensorFlow で提供されている GoogLeNet Inception v3 モデル使用しました。これは ImageNet でトレーニング済みのものです。

GoogLeNet グラフの Op 総数は 375 ありますが、Conv2D タイプの層に限定すれば 59 層でそれぞれ以下のような名前を持っています。そして * 印のついた層について画像を変形させてみます :

* conv2d0_pre_relu
* conv2d1_pre_relu
* conv2d2_pre_relu

* mixed3a_1x1_pre_relu
* mixed3a_3x3_bottleneck_pre_relu
* mixed3a_3x3_pre_relu
* mixed3a_5x5_bottleneck_pre_relu
* mixed3a_5x5_pre_relu
* mixed3a_pool_reduce_pre_relu

mixed3b_1x1_pre_relu
mixed3b_3x3_bottleneck_pre_relu
mixed3b_3x3_pre_relu
mixed3b_5x5_bottleneck_pre_relu
mixed3b_5x5_pre_relu
mixed3b_pool_reduce_pre_relu

* mixed4a_1x1_pre_relu
* mixed4a_3x3_bottleneck_pre_relu
* mixed4a_3x3_pre_relu
* mixed4a_5x5_bottleneck_pre_relu
* mixed4a_5x5_pre_relu
* mixed4a_pool_reduce_pre_relu

mixed4b_1x1_pre_relu
mixed4b_3x3_bottleneck_pre_relu
mixed4b_3x3_pre_relu
mixed4b_5x5_bottleneck_pre_relu
mixed4b_5x5_pre_relu
mixed4b_pool_reduce_pre_relu

mixed4c_1x1_pre_relu
mixed4c_3x3_bottleneck_pre_relu
mixed4c_3x3_pre_relu
mixed4c_5x5_bottleneck_pre_relu
mixed4c_5x5_pre_relu
mixed4c_pool_reduce_pre_relu

mixed4d_1x1_pre_relu
mixed4d_3x3_bottleneck_pre_relu
mixed4d_3x3_pre_relu
mixed4d_5x5_bottleneck_pre_relu
mixed4d_5x5_pre_relu
mixed4d_pool_reduce_pre_relu

mixed4e_1x1_pre_relu
mixed4e_3x3_bottleneck_pre_relu
mixed4e_3x3_pre_relu
mixed4e_5x5_bottleneck_pre_relu
mixed4e_5x5_pre_relu
mixed4e_pool_reduce_pre_relu

* mixed5a_1x1_pre_relu
* mixed5a_3x3_bottleneck_pre_relu
* mixed5a_3x3_pre_relu
* mixed5a_5x5_bottleneck_pre_relu
* mixed5a_5x5_pre_relu
* mixed5a_pool_reduce_pre_relu

* mixed5b_1x1_pre_relu
* mixed5b_3x3_bottleneck_pre_relu
* mixed5b_3x3_pre_relu
* mixed5b_5x5_bottleneck_pre_relu
* mixed5b_5x5_pre_relu
* mixed5b_pool_reduce_pre_relu

* head0_bottleneck_pre_relu
* head1_bottleneck_pre_relu

 
実験としては以下のノイズを乗せたグレー画像を入力サンプルとし、各層の重みをベースに変形した画像を示します :

 
以下がその変形画像のリストです。高い層(深い層)から低い層の順序になっています。
言うまでもなく、低い層では画像の変形がピクセル単位に局所化されます :

head1_bottleneck_pre_relu

head0_bottleneck_pre_relu


【ブロック 5B】

mixed5b_pool_reduce_pre_relu

mixed5b_5x5_pre_relu

mixed5b_5x5_bottleneck_pre_relu

mixed5b_3x3_pre_relu

mixed5b_3x3_bottleneck_pre_relu

mixed5b_1x1_pre_relu


【ブロック 5A】

mixed5a_pool_reduce_pre_relu

mixed5a_5x5_pre_relu

mixed5a_5x5_bottleneck_pre_relu

mixed5a_3x3_pre_relu

mixed5a_3x3_bottleneck_pre_relu

mixed5a_1x1_pre_relu


【ブロック 4A】

mixed4a_pool_reduce_pre_relu

mixed4a_5x5_pre_relu

mixed4a_5x5_bottleneck_pre_relu

mixed4a_3x3_pre_relu

mixed4a_3x3_bottleneck_pre_relu

mixed4a_1x1_pre_relu


【ブロック 3A】

mixed3a_pool_reduce_pre_relu

mixed3a_5x5_pre_relu

mixed3a_5x5_bottleneck_pre_relu

mixed3a_3x3_pre_relu

mixed3a_3x3_bottleneck_pre_relu

mixed3a_1x1_pre_relu


【Conv Layers】

conv2d2_pre_relu

conv2d1_pre_relu

conv2d0_pre_relu

 

以上

TensorFlow で Deep Dream 入門

TensorFlow で Deep Dream 入門

Deep Dream は人工知能が見る悪夢として有名ですが、実際には ConvNet (CNN) の特質を知るにはとても良い題材です。現在では様々な改良版が考案されていますが、オリジナルの Deep Dream は 2015 年 6 月に以下の Google Reseach Blog で公表されています :

Google Research Blog : Inceptionism: Going Deeper into Neural Networks

そして Caffe 実装が公開されていましたが、既に TensorFlow でも実装されています。
本記事では、最初に Caffe 実装による Deep Dream を試した後、TensorFlow 実装の Deep Dream の生成画像と比較してみます。

モデルはお馴染み GoogLeNet Inception モデルを ImageNet でトレーニングされたものが使用されています。Caffe 実装と TensorFlow 実装の生成画像の違いは本質的には別個にトレーニングされているためです。

Caffe による Deep Dream の実験

最初は ImageNet の城 (synset: Castle) 画像を元に、15 epochs トレーニング中の画像の変化を見てみます。
以下は最終生成画像です :

dd_ca04_0014

元画像 (ImageNet より)

1 epoch

dd_ca04

dd_ca04_0001

5 epochs

10 epochs

dd_ca04_0005

dd_ca04_0010

続いて、以下の元画像をベースに生成してみます。いずれも 5 epochs トレーニングしました :

dd_tree32

dd_oc10

dd_yaku01

dd_ca01
* 画像は ImageNet の URL とフリー素材を利用しており、元画像の版権は所有者に帰属しています。

 
Caffe 実装で利用しているモデルの場合、とにかく犬が現出する印象です。
(確認はしていませんが)ImageNet の画像に犬の画像が多いのかもしれません :
dd_tree32_0007

dd_oc10_0004

dd_yaku01_0004

以下の画像では、車輪が想起されているようです :
dd_ca01_0004

TensorFlow 実装との比較

上で Caffe 実装で試した元画像を入力として TensorFlow 実装で試してみました。
冒頭にも書きましたが、別個に事前トレーニングをしているために生成画像が異なっています。
また、Flower Dream と呼称される生成画像も併せて掲載しておきます :

tf_dd_tree32

tf_dd_tree32b

tf_dd_oc10

tf_dd_oc10b

tf_dd_yaku01

tf_dd_yaku01b

tf_dd_ca01

tf_dd_ca01b

 
以上

AI導入支援 #2 ウェビナー

スモールスタートを可能としたAI導入支援   Vol.2
[無料 WEB セミナー] [詳細]
「画像認識 AI PoC スターターパック」の紹介
既に AI 技術を実ビジネスで活用し、成果を上げている日本企業も多く存在しており、競争優位なビジネスを展開しております。
しかしながら AI を導入したくとも PoC (概念実証) だけでも高額な費用がかかり取組めていない企業も少なくないようです。A I導入時には欠かせない PoC を手軽にしかも短期間で認知度を確認可能とするサービの紹介と共に、AI 技術の特性と具体的な導入プロセスに加え運用時のポイントについても解説いたします。
日時:2021年10月13日(水)
会場:WEBセミナー
共催:クラスキャット、日本FLOW(株)
後援:働き方改革推進コンソーシアム
参加費: 無料 (事前登録制)
人工知能開発支援
◆ クラスキャットは 人工知能研究開発支援 サービスを提供しています :
  • テクニカルコンサルティングサービス
  • 実証実験 (プロトタイプ構築)
  • アプリケーションへの実装
  • 人工知能研修サービス
◆ お問合せ先 ◆
(株)クラスキャット
セールス・インフォメーション
E-Mail:sales-info@classcat.com