DeepLearning
Keras
TensorFlow

TimeDistributedでCNNを使った時の中間層の出力の抽出

0. はじめに

KerasでTimeDistributedを使った時に、中の畳込み層の出力を可視化したいと思ったんですが、
結構詰まったので記事にします。

1. 通常の中間層の出力の可視化

ここは実装していないんですが、以下の方法でできるみたいです。

get_feturemap.py
from keras import backend as K

#1層目の特長マップ
get_featurmap = K.function(model.layers[0].input, model.layers[0].get_output)

参考:https://github.com/keras-team/keras/issues/588

2. TimeDistributedの中身のConvolution層にアクセスする

GithubのTimeDistributedのコードを見てもget_outputがない...
どうやって中のConvolution層にアクセスしたものか...
TensorFlowだとノードでとりだせるから楽そうなんだけどなぁ

そこで,TensorFlowのページを見てみると
https://www.tensorflow.org/versions/r1.3/api_docs/python/tf/contrib/keras/layers/TimeDistributed#get_output_at
なんか使えそうなメソッドがあります。
このメソッドを使って中間層の出力を取り出します。

2.2 とりだす学習モデルの構成

私が取り出した時の構成と少し変えていますが、動作するはずです。
下にあるような構成の学習済みモデルを作ったとしてください。

Model_Architecture.py
from keras.layers.wrappers import TimeDistributed
from keras.layers.convolutional import Conv2D, MaxPooling2D
model = Sequential()
model.add(TimeDistributed(Conv2D(32, (3, 3),
                                         kernel_initializer="he_normal",
                                         activation='relu'), input_shape=self.input_shape))
model.add(TimeDistributed(Conv2D(32, (3, 3),
                                         kernel_initializer="he_normal",
                                         activation='relu')))
model.add(TimeDistributed(MaxPooling2D()))
model.add(TimeDistributed(Conv2D(32, (3, 3),
                                         kernel_initializer="he_normal",
                                         activation='relu')))
model.add(TimeDistributed(Conv2D(32, (3, 3),
                                         kernel_initializer="he_normal",
                                         activation='relu')))
model.add(TimeDistributed(MaxPooling2D()))
model.add(TimeDistributed(Flatten()))
model.add(Dense(512))
model.add(Dropout(0.5))
model.add(Dense(self.nb_classes, activation='softmax'))

2.3 Convolution層の出力を取り出す

get_featuremap_.py
from keras.models import load_model, Model
from keras import backend as K

# 学習済みモデルを読み込み
model = load_model(#saved_model)

#これでConvolution層にアクセスできる。
#get_output(0)の0はノード番号です。今回の場合0がConvolutionを表しています。
output_layer = model.layers[0].get_output_at(0)
#特徴マップ抽出関数を作ります.
get_output = K.function([model.layers[0].input], [output_layer])
#dataは入力データです.
#get_output()の出力は[array([..., ], dtype=tf.float32)とこんな構成になっているので、特徴マップを取り出したいときは[0]を指定してください。
output = get_output([data, ])[0]

上記の手順で,畳み込み層の出力が取り出せます。
最終出力ouputは(横, 縦, 枚数)と出てきますので注意してください.
これを自分の出力したいように整形、正規化してmatplotlibなりOpenCVなりで可視化してください.
ただし、注意ですが、出力枚数はフィルタの枚数分出力されます。
なので、可視化するときは1枚ずつだとか、3枚ずつにしないと可視化できません。
(32枚のチャネルって何!?ってなりますよね、一枚目が赤で、二枚目が緑で、三枚目が青、4枚目は透明度だとしても、5枚目からの扱いに困りますね)
TensorBoardのtf.summary.image()の出力も1チャネルか3チャネルか4チャネルの画像しか受け付けてくれません。

3. さいごに

読んでいただきありがとうございます.
皆様の問題解決につながれば幸いです。