Path: blob/master/site/ja/tutorials/generative/deepdream.ipynb
25118 views
Copyright 2019 The TensorFlow Authors.
DeepDream
このチュートリアルには、Alexander Mordvintsev によるこちらのブログ記事で説明された DeepDream の最小限の実装が含まれます。
DeepDream はニューラルネットワークが学習したパターンを視覚化する実験です。子供が雲を見てなんらかの形に解釈しようとするのと同様に、DeepDream は過解釈を行って、画像に見いだせるパターンの精度を強化します。
ネットワークを通じて画像を転送し、特定のレイヤーのアクティベーションに関して画像の勾配を計算することで行われています。画像は、これらのアクティベーションを変更しながら、ネットワークに見られるパターンを強化して、夢の中のようなイメージを作り出します。このプロセスは、InceptionNet と、映画「インセプション」の因んで、「インセプショニズム」と呼ばれています。
では、ニューラルネットワークに「夢を見させて」、画像に見いだすシュールなパターンを強化する方法を実演することにしましょう。
ドリーム化する画像を選択する
このチュートリアルでは、ラブラドールの画像を使用しましょう。
特徴抽出モデルを準備する
事前トレーニング済みの画像分類モデルをダウンロードして準備します。もともと DeepDream で使用されたモデルに似た InceptionV3 を使用します。任意の事前トレーニング済みのモデルを使用することができますが、レイヤー名を変更する場合は、以下のように調整する必要があります。
DeepDream の考え方は、レイヤーを選択して、画像がレイヤーを徐々に「刺激する」ように「損失」を最大化することです。追加する特徴量の複雑さは、あなたが選択するレイヤーによって異なり、レイヤーが低ければストロークや単純なパターンを生成し、レイヤーが深くなるほど、画像または画像全体の特徴がより洗練されることになります。
InceptionV3 アーキテクチャは非常に大型です(モデルアーキテクチャのグラフについては、TensorFlow の research リポジトリをご覧ください)。DeepDream では、対象のレイヤーは畳み込みが連結されている場所です。こういったレイヤーは InceptionV3 には 11 個あり、'mixed0' から 'mixed10' の名前が付けられています。異なるレイヤーを使用すると、異なった夢のような画像が生成されます。レイヤーが深くなるほどより高度な特徴(目や顔など)に対応し、浅いほどよりシンプルな特徴(エッジ、形状、テクスチャなど)に対応します。以下で選択するレイヤーを自由に試してみてください。ただし、レイヤーが深くなるほど(インデックスが高いレイヤー)、勾配の計算がより深くなるため、トレーニングに時間がかかることに注意してください。
損失を計算する
損失は、選択されたレイヤーのアクティベーションの和です。損失はレイヤーごとに正規化されるため、より大きなレイヤーからの貢献は小さなレイヤーを上回らないようになっています。通常、損失は、勾配降下法で最小化する量ですが、DeepDream では、勾配上昇法によってこの損失を最大化します。
勾配上昇法
選択したレイヤーの損失を計算したら、後は画像に関して勾配を計算し、それを元の画像に追加するだけです。
画像に勾配を追加すると、ネットワークが見るパターンの精度が上がります。各ステップで、ネットワークの特定のレイヤーのアクティベーションを徐々に刺激する画像を作成することになります。
これを行うメソッドは、パフォーマンスを得られるように tf.function
でラッピングされます。input_signature
を使用するため、さまざまな画像サイズまたは steps
/step_size
値で関数が再トレースされないようになっています。詳細は、具象関数ガイドをご覧ください。
メインのループ
オクターブを実行する
ここまでで非常に素晴らしいものではありますが、この最初の試行にはいくつかの問題があります。
出力にノイズがある(
tf.image.total_variation
損失で解消可能)。画像解像度が低い。
パターンが同じ粒度で発生しているように見える。
上記のすべての問題を解決するには、1 つのアプローチとして、異なるスケールで勾配上昇法を適用することが挙げられます。こうすれば、より小さなスケールで生成されたパターンをより高いスケールのパターンに統合して、追加の詳細で満たすことができます。
これを行うには、上述の勾配上昇法を実行してから、画像のサイズを増加し(これをオクターブと呼びます)、このプロセスを複数のオクターブで繰り返します。
オプション: タイルでスケールアップする
画像サイズが大きくなるにつれ、勾配計算の実行に必要な時間とメモリ量も高まるということに注意する必要があります。上記のオクターブ実装は、非常に大きな画像や多数のオクターブでは機能しません。
この問題を回避するには、画像をタイルに分割して、各タイルに対して勾配を計算することができます。
それぞれのタイル計算を行う前に画像にランダムシフトを適用すると、タイルの継ぎ目が現れなくなります。
ランダムシフトの実装から始めましょう。
以下は、前に定義した deepdream
関数のタイルバージョンです。
これを合わせると、スケーラブルなオクターブ対応の DeepDream 実装が得られます。
断然に良くなりました!オクターブ、オクターブスケール、アクティベーションされたレイヤーをいろいろ試して、DeepDream 化された画像の変化を確認してみてください。
このチュートリアルで紹介した考え方をさらに拡大した、ニューラルネットワークの視覚化と解釈を行う TensorFlow Lucid というものもありますので、ぜひお試しください。