Path: blob/master/site/ja/tutorials/generative/pix2pix.ipynb
25118 views
Copyright 2019 The TensorFlow Authors.
Licensed under the Apache License, Version 2.0 (the "License");
pix2pix: 条件付き GAN による画像から画像への変換
このチュートリアルでは、Isola et al による『Image-to-image translation with conditional adversarial networks』(2017 年)で説明されているように、入力画像から出力画像へのマッピングを学習する pix2pix と呼ばれる条件付き敵対的生成ネットワーク(cGAN)を構築し、トレーニングする方法を説明します。pix2pix はアプリケーションに依存しません。ラベルマップからの写真の合成、モノクロ画像からのカラー写真の生成、Google Maps の写真から航空写真への変換、スケッチ画像から写真への変換など、広範なタスクに適用できます。
この例のネットワークは、プラハにあるチェコ工科大学{:.external} の機械知覚センター{:.external} が提供する CMP Facade Database を使用して、建築物のファサード(正面部)の画像を生成します。この例を手短に紹介できるように、pix2pix の著者が作成したデータセットの事前処理済みのセット{:.external}を使用します。
pix2pix の cGAN では、入力画像で条件付けを行い、対応する出力画像を生成します。cGANs は『Conditional Generative Adversarial Nets』(2014 年 Mirza and Osindero)おいて初めて言及されました。
ネットワークのアーキテクチャには、以下の項目が含まれます。
U-Net{:.external} ベースのアーキテクチャを使用したジェネレータ。
畳みこみ PatchGAN 分類器で表現されたディスクリミネータ(pix2pix 論文{:.external} で提案)。
単一の V100 GPU で、エポックごとに約 15 秒かかる可能性があります。
以下は、ファサードデータセットを使って 200 エポックトレーニング(8 万ステップ)した後に pix2pix xGAN が生成した出力の例です。
TensorFlow とその他のライブラリをインポートする
データセットを読み込む
CMP Facade データベースのデータをダウンロードします(30 MB)。追加のデータセットはこちら{:.external} から同じ形式で入手できます。Colab では、ドロップダウンメニューから別のデータセットを選択できます。他のデータベースの一部は非常に大きいことに注意してください(edges2handbags
は 8 GB)。
それぞれの元の画像のサイズは 256 x 512
で、256 x 256
の画像が 2 つ含まれます。
実際の建物のファサードの写真と建築ラベル画像を分離する必要があります。すべてのサイズは 256 x 256
になります。
画像ファイルを読み込んで 2 つの画像テンソルを出力する関数を定義します。
入力(建築ラベル画像)画像と実際の(建物のファサードの写真)画像のサンプルをプロットします。
pix2pix 論文{:.external} に述べられているように、トレーニングセットを前処理するために、ランダムなジッターとミラーリングを適用する必要があります。
以下を行う関数を定義します。
256 x 256
の画像サイズをそれぞれより大きな高さと幅の286 x 286
に変更する。それをランダムに
256 x 256
にトリミングする。その画像をランダムに横方向(左右)に反転する(ランダムミラーリング)。
その画像を
[-1, 1]
の範囲に正規化する。
前処理された一部の出力を検査することができます。
読み込みと前処理がうまく機能することを確認したら、トレーニングセットとテストセットを読み込んで前処理するヘルパー関数を 2 つ定義しましょう。
tf.data
を使用して入力パイプラインを構築する
ジェネレータを構築する
pix2pix cGAN のジェネレータは、調整済みの U-Net{:.external} です。U-Net は、エンコーダ(ダウンサンプラー)とデコーダ(アップサンプラー)で構成されています。(これについては、画像のセグメンテーションチュートリアルと U-Net プロジェクトのウェブサイト{:.external} をご覧ください。)
エンコーダの各ブロック: 畳み込み -> バッチ正規化 -> Leaky ReLU
デコーダの各ブロック: 転置畳み込み -> バッチ正規化 -> ドロップアウト(最初の 3 つのブロックに適用) -> ReLU
エンコーダとデコーダ間にはスキップ接続があります(U-Net と同じ)。
ダウンサンプラー(エンコーダ)を定義します。
アップサンプラー(デコーダ)を定義します。
ダウンサンプラーとアップサンプラーを使用してジェネレータを定義します。
ジェネレータモデルアーキテクチャを可視化します。
ジェネレータをテストします。
ジェネレータ損失を定義する
pix2pix 論文{:.external} によると、GAN はデータに適応する損失を学習するのに対し、cGAN はネットワーク出力とターゲット画像とは異なる可能性のある構造にペナルティを与える構造化損失を学習します。
ジェネレータ損失は、生成された画像と 1 の配列のシグモイド交差エントロピー損失です。
pix2pix 論文には、生成された画像とターゲット画像間の MAE(平均絶対誤差)である L1 損失も言及されています。
これにより、生成された画像は、構造的にターゲット画像に似るようになります。
合計ジェネレータ損失の計算式は、
gan_loss + LAMBDA * l1_loss
で、LAMBDA = 100
です。この値は論文の執筆者が決定したものです。
以下に、ジェネレータのトレーニング手順を示します。
ディスクリミネータを構築する
pix2pix cGAN のディスクリミネータは、畳み込み PatchGAN 分類器です。pix2pix 論文{:.external} によると、これは、各画像のパッチが本物であるか偽物であるかの分類を試みます。
ディスクリミネータの各ブロック: 畳み込み -> バッチ正規化 -> Leaky ReLU
最後のレイヤーの後の出力の形状:
(batch_size, 30, 30, 1)
出力の各
30 x 30
の画像パッチは入力画像の70 x 70
の部分を分類します。ディスクリミネータは 2 つの入力を受け取ります。
入力画像とターゲット画像。本物として分類する画像です。
入力画像と生成された画像(ジェネレータの出力)。偽物として分類する画像です。
tf.concat([inp, tar], axis=-1)
を使用して、これら 2 つの入力を連結します。
ディスクリミネータを定義しましょう。
ディスクリミネータモデルアーキテクチャを可視化します。
ディスクリミネータをテストします。
ディスクリミネータ損失を定義する
discriminator_loss
関数は、本物の画像と生成された画像の 2 つの入力を取ります。real_loss
は 本物の画像と **1 の配列(本物の画像であるため)**のシグモイド交差エントロピー損失です。generated_loss
は、生成された画像と **0 の配列(偽物の画像であるため)**のシグモイド交差エントロピー損失です。total_loss
は、real_loss
とgenerated_loss
の和です。
以下に、ディスクリミネータのトレーニング手順を示します。
このアーキテクチャとハイパーパラメータについては、pix2pix 論文{:.external} をご覧ください。
オプティマイザとチェックポイントセーバーを定義する
画像を生成する
トレーニング中に画像を描画する関数を記述します。
テストセットの画像をジェネレータに渡します。
ジェネレータは入力画像を出力に変換します。
最後に、予測をプロットすると、出来上がり!
注意: training=True
は、テストデータセットでモデルを実行中にバッチ統計を行うために、ここに意図的に指定されています。training=False
を使用した場合、トレーニングデータセットから学習した蓄積された統計が取得されます(ここでは使用したくないデータです)。
関数をテストします。
トレーニング
各サンプルについて、入力は出力を生成します。
ディスクリミネータは input_image と生成された画像を最初の入力として受け取ります。2 番目の入力は input_image と target_image です。
次に、ジェネレータとディスクリミネータの損失を計算します。
さらに、ジェネレータとディスクリミネータの変数(入力)の両方に関して損失の勾配を計算し、これらをオプティマイザに適用します。
最後に、損失を TensorBoard にログします。
実際のトレーニングループ。このチュートリアルは 2 つ以上のデータセットを実行でき、データセットのサイズは非常に大きく異なるため、トレーニングループはエポックではなくステップで動作するようにセットアップされています。
ステップの回数をイテレートします。
10 ステップごとにドット(
.
)を出力します。1000 ステップごとに、表示を消去し、
generate_images
を実行して進行状況を示します。5000 ステップごとに、チェックポイントを保存します。
このトレーニングループは、TensorBoard に表示してトレーニングの進行状況を監視できるようにログを保存します。
ローカルマシンで作業する場合は、別の TensorBoard プロセスが起動します。ノートブックで作業する場合は、トレーニングを起動する前にビューアーを起動して、TensorBoard で監視します。
TensorFlow ビューアーを起動します(残念ながら、tensorflow.org では表示されません):
TensorBoard.dev で、このノートブックの前回の実行結果を閲覧できます。
最後に、トレーニングループを実行します。
GAN(または pix2pix のような cGAN)をトレーニングする場合、ログの解釈は、単純な分類または回帰モデルよりも明確ではありません。以下の項目に注目してください。
ジェネレータまたはディスクリミネータのいずれのモデルにも "won" がないことを確認してください。
gen_gan_loss
またはdisc_loss
のいずれかが非常に低い場合、そのモデルがもう片方のモデルを上回っていることを示しているため、組み合わされたモデルを正しくトレーニングできていないことになります。値
log(2) = 0.69
は、これらの損失に適した基準点です。パープレキシティ(予測性能)が 2 であるということは、ディスクリミネータが、平均して 2 つのオプションについて等しく不確実であることを表します。disc_loss
については、値が0.69
を下回る場合、ディスクリミネータは、本物の画像と生成された画像を組み合わせたセットにおいて、ランダムよりも優れていることを示します。gen_gan_loss
については、値が0.69
を下回る場合、ジェネレータがディスクリミネータを騙すことにおいて、ランダムよりも優れていることを示します。トレーニングが進行するにつれ、
gen_l1_loss
は下降します。