shimopino / papers-challenge

Paper Reading List I have already read
30 stars 2 forks source link

DF-GAN: Deep Fusion Generative Adversarial Networks for Text-to-Image Synthesis #202

Open shimopino opened 4 years ago

shimopino commented 4 years ago

論文へのリンク

[arXiv:2008.05865] DF-GAN: Deep Fusion Generative Adversarial Networks for Text-to-Image Synthesis

著者・所属機関

Ming Tao, Hao Tang, Songsong Wu, Nicu Sebe, Fei Wu, Xiao-Yuan Jing

投稿日時(YYYY-MM-DD)

2020-08-13

1. どんなもの?

1つのペアのGeneratorとDiscriminatorを使用して、テキストから高品質な画像の生成に成功した。本手法では、テキストと画像の意味が一致するように正則化をかける Matching-Aware zero-centered Gradient Penalty と、計算中に従来よりも多くテキスト情報を画像に組み込むことが可能な Deep Text-Image Fusion Block を提案している。

2. 先行研究と比べてどこがすごいの?

Text2Imageタスクで提案されているモデルの主流は、StackGANで提案された複数のGeneratorとDiscriminatorを使用して解像度の異なる画像を生成する階層構造モデルである。

階層構造のモデルには2つの弱点が存在する。

  1. 最初のGeneratorが後続のGeneratorに大きな影響を与えてしまうため、最初のGeneratorの学習に失敗すると後続のGeneratorの学習もうまくいかない
  2. 異なる解像度の画像ごとに設定するDiscriminatorを同時に最適化することが難しく、前段で画像が崩れたとして後続モデルで修正することができない

image

テキスト情報と画像情報を組み合わせる様々な手法が提案されているが、それぞれに弱点が存在している。

  1. Concatenation ただ単にテキストの特徴量を結合させただけではn、テキスト情報を有効に活用することができない
  2. Cross-Modal Attention Attentionを利用して画像の特徴量とテキストの特徴量に重み付けを行う
    1. 出力する画像の解像度が上がると、計算コストが急激に増大する
    2. ピクセル単位での関係性しか計算することができず、複数の物体が映っている画像のような複雑な関係性を表現できない
  3. Conditional Batch Normalization CBNでは特徴マップ中から、テキストに関連する特徴のみを強化することもできるが、アフィン変換による効率性を得ることができず、画像の生成中に数回しか適用することができない。

さらにこれらの手法以外にも、テキストから得られる特徴と画像から得られる特徴の一貫性を保つための手法として、AttnGANで提案されたDAMSMやCycle Consistency、Siamese Networkなどが提案されている。しかし、これらの手法は余分な学習コストを発生させてしまい、学習プロセス自体も複雑になってしまう。

本研究ではこれらの課題に対処するためにDF-GANを提案した。

  1. 階層構造の問題
    • ResNet構造のシンプルなバックボーンを採用
    • SAGANと同様に学習安定化のためヒンジ損失を採用
  2. テキスト情報と画像情報の組み合わせ方法
    • 画像の特徴量に関して、チャンネル方向にスケーリングとシフトを計算できる、複数の軽量なアフィン変換を使用するDFBlockを提案
  3. テキストの特徴と画像の特徴の一貫性
    • 一貫性を保持するためにMatching-Aware zero-centered Gradient Penalty (MA-GP) を提案した。

image

3. 技術や手法の"キモ"はどこにある?

3.1 Model Overview

DF-GANの全体像は以下になる。このモデルはGenerator、Discriminator、事前学習済みのText Encoderで構成されてる。

image

Generatorではまず、正規分布からサンプリングしたベクトルを最初の線形結合層を使用して (-1, 4, 4) 形状に変換する。次に特徴量の解像度を上げるUpBlockで構成されている。

このUpBlockでは、以下のようにテキスト情報をDFBlockを使用して画像の特徴に組み込んでいる。

Discriminatorでは画像のみを入力にとり、計算した特徴に対して次元数が合うように複製を行ったテキストの特徴を組み込んで、最終的に敵対的損失関数に適用している。

3.2 Simplified Text-to-Image Backbone

本モデルには、GeneratorとDiscriminatorで1つのペアを採用する。またSAGANと同様にヒンジ損失を採用している。

image

3.3 Matching-Aware Zero-Centered Gradient Penalty

Generatorがより現実に近く、またテキストの意味とも一致している画像を生成できるように新たな正則化手法 Matching-Aware zero-centered Gradient Penalty (MA-GP) を提案している。

従来の zero-centered Gradient Penalty (0-GP) では、実画像を学習させる際に以下の正則化を適用していた。

image

まずは以下の図のように、実画像に対応して低くなるDiscriminatorの損失値と生成画像に対応して高くなるDiscriminatorの損失値とを比較する。なおヒンジ損失を採用しているため、損失の値域は[-1, 1]になっている。

image

0-GP により実画像に対する勾配が最小化されるため、損失関数面での最小点に移動するように促すことができる。こうして実画像に対する損失関数面とその近傍を滑らかになる。結果としてGeneratorの学習がうまく進めば、この最小点に近い画像を生成できるようになる。

この性質から、Discriminatorは以下の2点を満たすようにすべきだと主張している。

  1. 実画像を最小点に、生成画像を高い値(今回だと1)に近づける
  2. 実画像に対応する損失関数面とその近傍を滑らかにする

では次に、この考え方をText2Imageタスクに応用する。

Discriminatorは4つのパターンの入力値を受け取る。

  1. 生成画像と意味の合うテキスト
  2. 生成画像と意味の合わないテキスト
  3. 実画像と意味の合うテキスト
  4. 実画像と意味の合わないテキスト

image

つまり、0-GP の考え方を適用するには、実画像と意味の合うテキストに対応する値を最小化させ、また損失関数面とその近傍を滑らかにしたうえで、他の組み合わせに関しては損失値が高くなるように設定する必要がある。

そこで実画像と意味の合うテキストに対して以下の Matching-Aware zero-centered Gradient Penalty (MA-GP) を提案している。(本研究ではk=2, p=6を設定している。)

image

この手法は、既存手法と比較して、テキストと画像の意味の一貫性が保たれているかどうかを計算するのに余分なネットワークを必要としない手法である。

3.4 One-way discriminator

StackGANやAttnGANといった従来の手法では、Discriminatorは入力された画像の特徴ベクトルを2つのブランチに分けていた。

  1. 画像が本物か偽物か識別するブランチ (unconditional)
  2. 画像の特徴ベクトルとテキストの特徴ベクトルの意味の一貫性を計算するブランチ (conditional)

image

本研究ではDiscriminatorを2つのブランチにわけることで、Generatorの学習の収束が遅くなり、またMA-GPの効果が減少してしまうことを発見している。

これは損失関数が2つに分かれることで、Discriminatorは実画像と対応するテキストに対する勾配γと、実画像のみに対する勾配βを受け取ることになり、最終的な勾配γ+βの方向がMA-GPが保証している実画像とテキストに対応する損失関数面の最小点と一致しなくなるからである。

そこで本研究では以下の図で示すように、1つのブランチのみを有するDiscriminatorを提案している。このDiscriminatorは画像の特徴ベクトルとテキストの特徴ベクトルを結合させた後で2つの畳み込み層を使用して、最終的に1つの敵対的損失を計算している。

image

これで勾配の方向を、MA-GPと同様に実画像とテキストに対応した損失関数面の最小点に向くように計算することができる。

3.5 Deep Text-Image Fusion Block

また本研究では画像生成中に、画像の特徴ベクトルとテキストの特徴ベクトルを効率的に組み合わせるDFBlockを提案している。DFBlockはアフィン変換層・ReLU層・畳み込み層で構成されている。

image

特徴マップに対するアフィン変換は、バッチ正規化などの正則化手法で広く使用されている。バッチ正規化では、まず特徴マップをバッチ間の平均と分散で正規化を行い、学習パラメータであるγとβを使って特徴マップのシフト・スケーリングを行うためにアフィン変換を適用している。

CBNでは特徴マップ以外にもラベルなどの外部情報を使用して、アフィン変換のパラメータを学習させている。これで特徴マップを、外部情報に基づいてスケーリング等を行うことが可能になる。

本研究ではCBNで使用されているアフィン変換の効果の分離を行っている。条件付きでの画像生成において特徴マップを正規化することは重要ではないと仮定した。実際にText2Imageタスクにおいては正規化を行うことで学習効率が下がっていることを確認している。

以下の図のように1つの残差ブロックに対して2つのDFBlockを採用している。

image

2つ存在するDFBlockのうち、後半のブロックでのバッチ正規化は、前半のブロックで行ったアフィン変換の効果を下げてしまうと仮定した。またバッチ正規化は特徴マップを正規分布に変換する操作だと考えると、分布の変換を行うアフィン変換とは逆の操作を行っており、バッチ間での特徴マップの距離を小さくすることができる。

これは条件付き画像生成では利点とはならない。

そこでCBNからアフィン変換部部のみを取り出して特徴マップに適用した。アフィン変換のパラメータは、文ベクトルを入力にした1層のMLPから予測を行うようにしている。

image

チャンネルごとのシフト・スケーリングを通して、テキストの意味に合うような画像を生成できる。

image

このDFBlockでの計算の流れを図示すると以下のようになる。

image

さらにCBNからアフィン変換のみを抽出することで、画像の特徴ベクトルとテキストの特徴ベクトルを自由に組み合わせることが可能となる。

結果としてこのDFBlockを使用することで、テキストと画像の特徴を組み合わせる過程をより深層化させることができる。深層化の利点は以下の3つになる。

  1. Generatorは様々なスケールでテキストと画像の特徴を組み合わせることが可能になる
  2. 深層化させて非線形性を増やすことで異なるテキストから一貫性のある画像を生成可能になる
  3. 複数のアフィン変換を重ねることで、より複雑で効率的な組み合わせが可能になる

本手法とCBNの大きな違いは以下の2点である

  1. 特徴マップの正規化を行わない。これで画像生成中にバッチ間での特徴マップの差が小さくなることを防ぎ、アフィン変換の効率が下がらないようにしている。
  2. アフィン変換とReLUをいくつも積み重ねることで、テキストと画像の特徴をより複雑に組み合わせることが可能になる。

4. どうやって有効だと検証した?

4.1 実験条件

4.2 結果

image

image

image

image

5. 議論はあるか?

shimopino commented 4 years ago

https://github.com/tobran/DF-GAN

shimopino commented 4 years ago

アフィン変換では、文ベクトルを条件にアフィン変換のパラメータをMLPで計算し、前層の特徴マップに対してチャンネルごとに適用している。 (著者実装では、隠れ層が2層のMLPで構成されている)

class Affine(nn.Module):
    """Affine Transformation extracted from Conditional BatchNorm

    Args:
        num_features (int): the channel dimension of  the input visual feature map
        sentence_features (int): the channel dimension of the input sentence vector
    """
    def __init__(self, num_features, sentence_features=256):
        super().__init__()

        self.gamma = nn.Sequential(OrderedDict([
            ('linear1',nn.Linear(sentence_features, sentence_features)),
            ('relu1',nn.ReLU(inplace=True)),
            ('linear2',nn.Linear(sentence_features, num_features)),
            ]))
        self.beta = nn.Sequential(OrderedDict([
            ('linear1',nn.Linear(sentence_features, sentence_features)),
            ('relu1',nn.ReLU(inplace=True)),
            ('linear2',nn.Linear(sentence_features, num_features)),
            ]))

        nn.init.zeros_(self.gamma.linear2.weight.data)
        nn.init.ones_(self.gamma.linear2.bias.data)
        nn.init.zeros_(self.beta.linear2.weight.data)
        nn.init.zeros_(self.beta.linear2.bias.data)

    def forward(self, x, y=None):
        """transform the input featue map conditioned by sentence vector

        Args:
            x (Tensor): the input feature map of shape [B, C, H, W]
            y (Tensor): the sentence vector of shape [B, D]
        Returns:
            output (Tensor): the output feature map of shape [B, C, H, W]
        """

        # if there isn't the sentence vector, return the input feature map
        if y is None:
            return x

        gamma = self.gamma(y)
        beta = self.beta(y)        

        # if the tensor doesn't have the batch dimension, expand it.
        if weight.dim() == 1:
            weight = weight.unsqueeze(0)
        if bias.dim() == 1:
            bias = bias.unsqueeze(0)

        size = x.size()
        # broadcasting with height and width dimension
        weight = weight.unsqueeze(-1).unsqueeze(-1).expand(size)
        bias = bias.unsqueeze(-1).unsqueeze(-1).expand(size)
        output = weight * x + bias
        return output
shimopino commented 4 years ago

次にこのアフィン変換を使用してDFBlockを構築する

class DFBlock(nn.Module):
    """DFBlock
    Affine -> ReLU -> Affine -> ReLU -> Conv

    Args:
        in_ch (int): the channel dimension of  the input visual feature map
        out_ch (int): the channel dimension of  the output visual feature map
        sentence_features (int): the channel dimension of the input sentence vector
    """
    def __init__(self, in_ch, out_ch, sentence_features=256):
        super().__init__()

        self.affine1 = Affine(in_ch, sentence_features)
        self.activation1 = nn.ReLU(inplace=True)
        self.affine2 = Affine(in_ch, sentence_features)
        self.activation2 = nn.ReLU(inplace=True)
        self.conv = nn.Conv2d(in_ch, out_ch, kernel_size=3, stride=1, padding=1)

    def forward(self, x, y=None):
        """forward through DFBlock

        Args:
            x (Tensor): the input feature map of shape [B, C, H, W]
            y (Tensor): the sentence vector of shape [B, D]
        Returns:
            output (Tensor): the output feature map of shape [B, C, H, W]
        """

        h = self.activation1(self.affine1(x, y))
        h = self.activation2(self.affine2(x, y))
        h = self.conv(h)

        return h