5.5 ニューラルスタイル変換

CycleGAN では、訓練セットの画像は対(pair)になっている必要はない。

ニューラルスタイル変換では、訓練セットを一切持たずに画像の画風を変換する。 以下の3つの異なる損失関数の和を最小化する。

  • コンテンツ損失 ... 合成画像は、ベース画像と同じコンテンツを含んでいるようにしたい。
  • スタイル損失 ... 合成画像は、全般的ンいスタイル画像と同じ画風になるようにしたい。
  • 全変動損失 ... 合成画像は、ピクセルのあつまりのようではなく、滑らかに見えるようにした。

5.5.1 コンテンツ損失

画像のテーマと、その内容の全体的な配置、との観点から、2つの画像がどれだけ異なっているかを計測する。 ピクセル単位の比較ではなく、もっと大きな単位での比較が必要となる。 既に訓練されたディープラーニングのモデルを用いることによって、与えられた入力画像の高レベルの特徴を抽出できる。 ベース画像に対するこの出力と、現時点での合成画像との平均2乗誤差を計算すればよい。

本例では、既に訓練済みのネットワークとして VGG-19 を使う。

2つの画像の間のコンテンツ損失を計算するプログラムは Keras の公式リポジトリにある ニューラルスタイル変換の例 https://keras.io/examples/generative/neural_style_transfer/ を参照するとよい。 本にはリンクが http://bit.ly/2FlVU0P であると記述されていたが 2021/10/17 現在上記URLに移動したようだ)。

5.5.2 スタイル損失

スタイル損失を定量化することは難しい問題である。 ニューラルスタイルの原論文で示されているのは「 通常スタイルが似ている画像は、所定の層における特徴マップ間の相関パターンが同じである」 という考え方を取っている。

ニューラルネットワークのある層がある特徴について特定するように学習されているとする。 そのような特徴が3種類あったとする。 3つの入力に対して、3特徴それぞれの特徴マップが次の例のようであったとする。

>>
画像特徴1特徴2特徴3
画像1
1 0 0 0 0
2 1 0 0 0
2 2 1 0 0
2 2 2 1 0
1 0 0 0 0
2 1 0 0 0
2 1 1 1 0
2 2 2 1 0
2 2 0 1 2
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
画像2
0 0 0 0 0
2 2 2 2 1
0 2 2 2 1
0 0 0 0 0
0 0 0 0 1
1 2 2 2 1
0 2 2 2 1
0 0 0 0 0
0 0 0 2 0
0 0 0 2 0
1 0 0 2 0
2 2 2 2 2
画像3
2 2 2 2 2
2 1 1 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 2 2 2 2
2 2 2 2 2
2 2 2 2 2
0 0 0 0 0
1 1 1 2 2
2 2 2 2 2
2 2 2 2 2

特徴1のマップおよび特徴2のマップが似た分布をしていることから、 画像1と画像2は互いスタイルが似ているといえる。

2つの特徴マップを平坦化(Flatten())して内積を取れば、どれだけ同じように活性化しているかを計算できる。 ある層のすべての可能な特徴ペアの間の内積を格納した行列を Gram 行列と呼ぶ。 スタイルが似ている画像1と画像2が、似たGram行列を持っている。

したがって、スタイル損失を計算するために必要なことは、 ネットワーク中の一連の層で ベース画像と合成画像の両方に対するGram行列 (GM) を計算し、 2乗誤差の和を使ってその類似性を比べることである。

ある層 $l$ でのサイズ $M_1$ $(\mbox{高さ}\times\mbox{幅})$ , $N_1$ チャネルのベース画像 $S$ と生成された画像 $G$ の間のスタイル損失:
$\displaystyle L_{GM} (S, G, l) = \frac{1}{4 N_{l}^{2} M_{l}^{2}} \sum_{ij} (GM[l](S)_{ij} - GM[l](G)_{ij})^2$

全スタイル損失は、各層のチャネル数 $N_l$ とサイズ $M_l$ を考慮して以下の通り。
$\displaystyle L_{style}(S,G) = \sum_{l=0}^{L} L_{GM} (S, G, l)$

5.5.3 全変動損失

全変動損失は合成画像内のノイズを計測する。 画像を1ピクセルだけ右にずらして、元の画像との間の2乗誤差を計算する。 また、1ピクセルだけ下にずらして、元の画像との間の2乗誤差を計算する。 このわが全変動損失である。

Neural style transfer

以下、Keras 公式の Neural style transfer https://keras.io/examples/generative/neural_style_transfer/ にしたがって話を進める。

Introduction

Style Transfer は、元画像と同じコンテンツを持ちながら、異なる画像のスタイル(芸術的な意味での)を備えた画像を生成する。

[自分へのメモ] VGG16 や VGG19 の入力画像サイズのデフォルトは 224x244x3 である。 幅と高さはそれぞれ 32 以上である必要がある。

In [1]:
# Setup

import tensorflow as tf
import numpy as np

base_image_path = tf.keras.utils.get_file(
    "paris.jpg",
    "https://i.imgur.com/F28w3Ac.jpg"
)
style_reference_image_path = tf.keras.utils.get_file(
    "starry_night.jpg",
    "https://i.imgur.com/9ooB60I.jpg"
)
result_prefix = "paris_generated"

# weights of different loss components
total_variation_weight = 1e-6
style_weight = 1e-6
content_weight = 2.5e-8

# Dimensions of the generated picture.
base_img = tf.keras.preprocessing.image.load_img(base_image_path)
width, height = base_img.size
img_nrows = 400
img_ncols = int(width * img_nrows / height)
In [2]:
style_img = tf.keras.preprocessing.image.load_img(style_reference_image_path)
In [3]:
# 画像を表示する
%matplotlib inline
import matplotlib.pyplot as plt

fig, ax = plt.subplots(2,1,figsize=(8,6*2))

ax[0].imshow(base_img)
ax[0].axis('off')

ax[1].imshow(style_img)
ax[1].axis('off')

plt.show()