Activation Maximizationとは
CNNのそれぞれの畳み込み層は、入力画像内によく似たパターンを見つけると出力を最大化するいくつかの学習済みテンプレートマッチングフィルタを所有しています。 最初の畳み込み層は簡単に解釈で、単に重みを画像として可視化するだけです。 畳み込み層がしていることを見るためには、入力ピクセルにフィルタを適用するのがシンプルな方法です。 後続の畳み込みフィルタが前の畳み込みフィルタの出力を処理する(いくつかのパターンの存在有無を示す)ため、それらの解釈が難しくなります。
ActivationMaximizationの背景にあるアイデアは今となってはシンプルで、フィルタの出力活性化を最大にする入力画像を生成することです。 つまり下記を計算すること。
そして、その推定値を使って入力を更新することです。 ActivationMaximization損失関数はフィルタの活性化を大きくするために、その出力を小さくします(勾配降下の反復中に損失を最小化します)。 これにより特定の入力パターンに対して活性化するフィルタを理解することができます。 例えば、入力画像内にある'眼'によって活性化するEyeフィルタがあるかもしれません。
使い方
ActivationMaximizationを実行するための2つのAPIがあります。
- visualize_activation:活性化を可視化するための汎用APIです。
- visualize_activation_with_losses:いくつかのカスタムな重み付き損失の最小化を扱うような研究利用向けです。
examples/にあるコードを参照してください。
シナリオ
APIはとても一般的な目的で、幅広く様々なシナリオで利用可能です。 もっとも一般的なユースケースを下記にリストアップします:
分類出力をおこなう全結合層の可視化
ネットワークが過学習(または未学習)なのか、適切に一般化できているのかをどのように評価できますか? 入力画像を与えると、CNNはそれが猫なのか鳥なのかなどを分類できます。 鳥であることの意味を正しい概念で捕らえているかどうか確認できますか?
それらの問いに対する1つの解は、逆の問いかけをすることです:
鳥クラスに対応する最終層の出力を最大化する入力画像を生成する。
これは最終層をlayer_idx
で指し、filter_indices
に望む出力分類を設定することで実現できます。
- 複数クラス分類問題では、
filter_indices
は1つのクラスを指すことができます。 "猫 魚"がどのように見えるかを確認するために複数の分類を指すことも可能です。 - 複数ラベル分類では、適切な
filter_indices
を指定するだけです。
回帰出力をおこなう全結合層の可視化
クラス活性化の可視化とは異なり、回帰出力では、filter_indices
の出力を
- 増加させる入力
- 減少させる入力
の可視化ができます。
例えばリンゴを数えるモデルを学習して、その回帰出力を増加させることは入力画像内のリンゴを増やすことと一致するはずです。
同様に回帰出力を減らすこともできます。
これはgrad_modifier
オプションを使うことで実現できます。
名前から連想するように、入力に関する損失の勾配を変更するために使われます。
デフォルトでは、ActivationMaximization
損失は出力を増加させるために使われます。
grad_modifier='negate'
を設定することで勾配の符号反転ができ、これにより出力値を減少させることができます。
gradient_modifiersはとても強力で、他の可視化APIでもよく使われます。
畳み込みフィルタの可視化
layer_idx
が畳み込み
層を指すことで、フィルタを活性化するパターンを可視化できます。
これはフィルタがどう計算されているかを理解するのに役立ちます。
ここではfilter_indices
はレイヤ内の畳み込み
フィルタのインデックスを参照します。
高度な使い方
backprop_modifiersを使えば、誤差逆伝播の振る舞いを変更することができます。
例えば、backprop_modifier='relu'
を使うことで正の勾配だけを伝播させるよう微調整できます。
このパラメータを関数に渡して、クレイジーな研究アイデアの実装に使って下さい。 :-)
Tipsとトリック
- どうしようもない可視化を得てしまったら、勾配降下反復中の様々なロスを確認するために
verbose=True
を設定してみて下さい。 デフォルトでは、visualize_activation
はより自然な画像を得るためにTotalVariation
とLpNorm
の正則化を使います。ActivationMaximization Loss
が正則化損失の重み係数に支配され、値が前後に跳ねる様子を見ることができるでしょう。 全ての重み係数をゼロに設定して、徐々にTV損失の重み係数を増やしてみてください。 - よりシャープな画像を得るために、Jitter入力修飾子を使って下さい。
- 回帰モデルは通常、意味ある入力画像を生成するために十分な勾配情報を提供しません。
もし入力画像が意味をなさい場合は、
seed_input
を使って初期値を与えてみてください。 - あなたが発見した有用なTipsやトリックを、PullRequestでkeras-visに追加することを検討してください。