フィルターを視覚化する の方法として、畳み込みニューラルネットワーク(CNN)の単一の畳み込みフィルターの入力レイヤーに関する勾配を見つける必要があります。
Python Caffe のインターフェース この例 のインターフェースなど)で訓練されたネットワークがある場合、どうすれば入力レイヤーのデータに関する変換フィルターの勾配を見つけますか?
編集:
answer by cesans に基づいて、以下のコードを追加しました。入力レイヤーのサイズは_[8, 8, 7, 96]
_です。私の最初の変換レイヤーである_conv1
_には、サイズが_1x5
_の11個のフィルターがあり、その結果、次元は_[8, 11, 7, 92]
_になります。
_net = solver.net
diffs = net.backward(diffs=['data', 'conv1'])
print diffs.keys() # >> ['conv1', 'data']
print diffs['data'].shape # >> (8, 8, 7, 96)
print diffs['conv1'].shape # >> (8, 11, 7, 92)
_
出力からわかるように、net.backward()
によって返される配列の次元は、Caffeのレイヤーの次元と同じです。いくつかのテストを行った結果、この出力はdata
レイヤーと_conv1
_レイヤーのそれぞれに関する損失の勾配であることがわかりました。
ただし、私の質問は、入力レイヤーのデータに関する単一のconvフィルターの勾配をどのように見つけるかでした。これは別のことです。どうすればこれを達成できますか?
Caffe netは、2つの「ストリーム」の数を操作します。
1つ目はデータ「ストリーム」です。つまり、画像とラベルがネットを介してプッシュされます。これらの入力がネットを介して進行すると、それらは高レベルの表現に変換され、最終的に(分類タスクで)クラス確率ベクトルに変換されます。
2番目の「ストリーム」は、さまざまなレイヤーのパラメーター、畳み込みの重み、バイアスなどを保持します。これらの数/重みは、ネットのトレーニングフェーズ中に変更および学習されます。
これら2つの「ストリーム」が果たす根本的に異なる役割にもかかわらず、カフェはそれらを格納および管理するために同じデータ構造blob
を使用します。
ただし、各レイヤーには2つのdifferent blobsベクトルがあり、各ストリームに1つあります。
これが私が明確にしたいと思う例です:
import caffe
solver = caffe.SGDSolver( PATH_TO_SOLVER_PROTOTXT )
net = solver.net
今見れば
net.blobs
ネットの各レイヤーの「カフェブロブ」オブジェクトを格納する辞書が表示されます。各blobには、データと勾配の両方を格納するスペースがあります
net.blobs['data'].data.shape # >> (32, 3, 224, 224)
net.blobs['data'].diff.shape # >> (32, 3, 224, 224)
そして、畳み込み層の場合:
net.blobs['conv1/7x7_s2'].data.shape # >> (32, 64, 112, 112)
net.blobs['conv1/7x7_s2'].diff.shape # >> (32, 64, 112, 112)
net.blobs
は最初のデータストリームを保持します。その形状は、結果のクラス確率ベクトルまでの入力画像の形状と一致します。
一方、net
の別のメンバーを見ることができます
net.layers
これは、さまざまなレイヤーのパラメーターを格納するカフェベクトルです。
最初のレイヤー('data'
レイヤー)を見る:
len(net.layers[0].blobs) # >> 0
入力レイヤーに保存するパラメーターはありません。
一方、最初の畳み込み層
len(net.layers[1].blobs) # >> 2
ネットは、フィルターの重み用に1つのblobを保存し、一定のバイアス用に別のblobを保存します。はい、どうぞ
net.layers[1].blobs[0].data.shape # >> (64, 3, 7, 7)
net.layers[1].blobs[1].data.shape # >> (64,)
ご覧のとおり、このレイヤーは3チャネルの入力画像に対して7x7の畳み込みを実行し、64個のフィルターがあります。
では、グラデーションを取得する方法は?まあ、あなたが指摘したように
diffs = net.backward(diffs=['data','conv1/7x7_s2'])
dataストリームの勾配を返します。これは
np.all( diffs['data'] == net.blobs['data'].diff ) # >> True
np.all( diffs['conv1/7x7_s2'] == net.blobs['conv1/7x7_s2'].diff ) # >> True
(TL; DR)パラメータの勾配が必要な場合、これらはパラメータとともにnet.layers
に格納されます。
net.layers[1].blobs[0].diff.shape # >> (64, 3, 7, 7)
net.layers[1].blobs[1].diff.shape # >> (64,)
レイヤーの名前とインデックスをnet.layers
ベクトルにマッピングするのに役立つように、net._layer_names
を使用できます。
更新フィルター応答を視覚化するための勾配の使用に関して:
通常、勾配はスカラー関数に対して定義されます。損失はスカラーであるため、スカラー損失に対するピクセル/フィルターの重みの勾配について説明できます。この勾配は、ピクセル/フィルターの重みごとに1つの数値です。
特定の内部の隠しノードの最大の活性化で生じる入力を取得したい場合、損失は特定の活性化の測定値である「補助」ネットが必要です視覚化する非表示ノード。この補助ネットを取得したら、任意の入力から開始して、入力層への補助損失の勾配に基づいてこの入力を変更できます。
update = prev_in + lr * net.blobs['data'].diff
backward()
パスを実行すると、任意のレイヤーでグラデーションを取得できます。関数を呼び出すときにレイヤーのリストを指定するだけです。データレイヤーでグラデーションを表示するには:
net.forward()
diffs = net.backward(diffs=['data', 'conv1'])`
data_point = 16
plt.imshow(diffs['data'][data_point].squeeze())
すべてのレイヤーを強制的に逆方向に実行したい場合があります。force_backward
モデルのパラメータ。
https://github.com/BVLC/caffe/blob/master/src/caffe/proto/caffe.proto