ケラス、各レイヤーの出力を取得するには?


155

CNNを使用してバイナリ分類モデルをトレーニングしましたが、これが私のコードです

model = Sequential()
model.add(Convolution2D(nb_filters, kernel_size[0], kernel_size[1],
                        border_mode='valid',
                        input_shape=input_shape))
model.add(Activation('relu'))
model.add(Convolution2D(nb_filters, kernel_size[0], kernel_size[1]))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=pool_size))
# (16, 16, 32)
model.add(Convolution2D(nb_filters*2, kernel_size[0], kernel_size[1]))
model.add(Activation('relu'))
model.add(Convolution2D(nb_filters*2, kernel_size[0], kernel_size[1]))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=pool_size))
# (8, 8, 64) = (2048)
model.add(Flatten())
model.add(Dense(1024))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(2))  # define a binary classification problem
model.add(Activation('softmax'))

model.compile(loss='categorical_crossentropy',
              optimizer='adadelta',
              metrics=['accuracy'])
model.fit(x_train, y_train,
          batch_size=batch_size,
          nb_epoch=nb_epoch,
          verbose=1,
          validation_data=(x_test, y_test))

そして、ここでは、TensorFlowと同じように各レイヤーの出力を取得したいのですが、どうすればよいですか?

回答:


182

以下を使用することにより、任意のレイヤーの出力を簡単に取得できます。 model.layers[index].output

すべてのレイヤーでこれを使用します。

from keras import backend as K

inp = model.input                                           # input placeholder
outputs = [layer.output for layer in model.layers]          # all layer outputs
functors = [K.function([inp, K.learning_phase()], [out]) for out in outputs]    # evaluation functions

# Testing
test = np.random.random(input_shape)[np.newaxis,...]
layer_outs = [func([test, 1.]) for func in functors]
print layer_outs

注:ドロップアウトの使用をシミュレートするlearning_phaseよう1.layer_outsそうでない場合は使用0.

編集:(コメントに基づく)

K.function 与えられた入力でシンボリックグラフから出力を取得するために後で使用されるtheano / tensorflowテンソル関数を作成します。

K.learning_phase()Dropout / Batchnomalizationのような多くのKerasレイヤーがトレーニングとテスト時間中に動作を変更するためにそれに依存するので、今は入力として必要です。

したがって、コードからドロップアウトレイヤーを削除した場合は、次のように使用できます。

from keras import backend as K

inp = model.input                                           # input placeholder
outputs = [layer.output for layer in model.layers]          # all layer outputs
functors = [K.function([inp], [out]) for out in outputs]    # evaluation functions

# Testing
test = np.random.random(input_shape)[np.newaxis,...]
layer_outs = [func([test]) for func in functors]
print layer_outs

編集2:より最適化

前の答えは、各関数の評価に関してデータがCPU-> GPUメモリに転送されるように最適化されておらず、テンソル計算を下位層に対して繰り返し行う必要があることに気づきました。

代わりに、複数の関数を必要とせず、すべての出力のリストを提供する単一の関数を使用するので、これははるかに優れた方法です。

from keras import backend as K

inp = model.input                                           # input placeholder
outputs = [layer.output for layer in model.layers]          # all layer outputs
functor = K.function([inp, K.learning_phase()], outputs )   # evaluation function

# Testing
test = np.random.random(input_shape)[np.newaxis,...]
layer_outs = functor([test, 1.])
print layer_outs

2
先生、あなたの答えは良いK.function([inp]+ [K.learning_phase()], [out])です、あなたのコードで何を意味しますか?
GoingMyWay 2017年

すばらしい答え、次のnp.random.random(input_shape)[np.newaxis,...]ように書くこともできますnp.random.random(input_shape)[np.newaxis,:]
Tom

K.functionとは何ですか?どのようにGPU(MPI?)に渡されますか?舞台裏には何がありますか?CUDAとの対話はどうですか?ソースコードはどこにありますか?
Stav Bodik

3
@StavBodikモデルはK.function hereを使用して予測関数を構築し、predictはここの予測ループそれを使用します。予測は、バッチサイズのループを予測します(設定されていない場合、デフォルトは32です)が、GPUメモリの制約を緩和するためです。なぜあなたが観察しているのmodel.predictが速いのかはわかりません。
indraforyou 2018

1
これを取得しています:InvalidArgumentError:S_input_39:0は、フィードもフェッチもされています。...アイデアを持っている人はいますか?
mathtick

137

https://keras.io/getting-started/faq/#how-can-i-obtain-the-output-of-an-intermediate-layerから

簡単な方法の1つは、関心のあるレイヤーを出力する新しいモデルを作成することです。

from keras.models import Model

model = ...  # include here your original model

layer_name = 'my_layer'
intermediate_layer_model = Model(inputs=model.input,
                                 outputs=model.get_layer(layer_name).output)
intermediate_output = intermediate_layer_model.predict(data)

または、特定の入力を指定すると特定のレイヤーの出力を返すKeras関数を構築できます。次に例を示します。

from keras import backend as K

# with a Sequential model
get_3rd_layer_output = K.function([model.layers[0].input],
                                  [model.layers[3].output])
layer_output = get_3rd_layer_output([x])[0]

私があなたに2つ^をあげることができれば^、あなたがたくさんの入力を持っているとき、この方法はすごく便利です。
Dan Erez

上記のコードからは明らかですが、私の理解を再確認するだけです。既存のモデルからモデルを作成した後(すでにトレーニング済みであると仮定)、新しいモデルでset_weightsを呼び出す必要はありません。あれは正しいですか?
JZ

どのような違いがあるlayer_output = get_3rd_layer_output([X, 0])[0]layer_output = get_3rd_layer_output([X, 1])[0]ドキュメントは、列車モードとテストモード言及
ジェイソン

申し訳ありませんが、このモデルが正確に何をしているのか説明してもらえますか?あなたもそれを訓練する必要がありますか?私はそれにどんな図も想像できません。別のモデルの入力レイヤーを追加してから、その他のモデルのランダムな中間レイヤーを出力として追加し、それに入力をフィードしますか?なぜ元のモデルにフィードする代わりにこれを実行して、その中にある中間層に直接アクセスするのですか?なぜこの奇妙なモデルを作成するのですか?そして、それは出力に影響しませんか?学習を試みたり、トレーニングを必要としたりしませんか、またはレイヤーは元のモデルから事前にトレーニングされた独自の重みをもたらしますか?
PedroD

19

このスレッドのすべての良い答えに基づいて、各レイヤーの出力を取得するライブラリを作成しました。すべての複雑さを抽象化し、可能な限りユーザーフレンドリーになるように設計されています。

https://github.com/philipperemy/keract

ほとんどすべてのエッジケースを処理します

それが役に立てば幸い!


8

以下は私には非常にシンプルに見えます:

model.layers[idx].output

上記はテンソルオブジェクトなので、テンソルオブジェクトに適用できる操作を使用して変更できます。

たとえば、形状を取得するには model.layers[idx].output.get_shape()

idx はレイヤーのインデックスであり、次の場所から見つけることができます model.summary()


1
この答えの何が問題になっていますか?なぜこれがトップアンサーとして支持されないのですか?
ブラックジャック21

1
データフレームではなくテンソルオブジェクトを返します。tfオブジェクトは扱いがおかしいです。
HashRocketSyntax

7

私はこの関数を自分で(Jupyterで)作成し、indraforyouに触発されましたの回答。すべてのレイヤー出力を自動的にプロットします。画像の形状は(x、y、1)である必要があります。1は1チャネルを表します。プロットするには、plot_layer_outputs(...)を呼び出すだけです。

%matplotlib inline
import matplotlib.pyplot as plt
from keras import backend as K

def get_layer_outputs():
    test_image = YOUR IMAGE GOES HERE!!!
    outputs    = [layer.output for layer in model.layers]          # all layer outputs
    comp_graph = [K.function([model.input]+ [K.learning_phase()], [output]) for output in outputs]  # evaluation functions

    # Testing
    layer_outputs_list = [op([test_image, 1.]) for op in comp_graph]
    layer_outputs = []

    for layer_output in layer_outputs_list:
        print(layer_output[0][0].shape, end='\n-------------------\n')
        layer_outputs.append(layer_output[0][0])

    return layer_outputs

def plot_layer_outputs(layer_number):    
    layer_outputs = get_layer_outputs()

    x_max = layer_outputs[layer_number].shape[0]
    y_max = layer_outputs[layer_number].shape[1]
    n     = layer_outputs[layer_number].shape[2]

    L = []
    for i in range(n):
        L.append(np.zeros((x_max, y_max)))

    for i in range(n):
        for x in range(x_max):
            for y in range(y_max):
                L[i][x][y] = layer_outputs[layer_number][x][y][i]


    for img in L:
        plt.figure()
        plt.imshow(img, interpolation='nearest')

モデルに複数の入力がある場合はどうなりますか?入力をどのように指定しますか?
Antonio Sesto 2017

この行では:layer_outputs_list = [op([test_image、1.])。1.は0である必要がありますか?1はトレーニングを表し、0はテストを表しています。じゃないですか?
Kongsea、2017

これは私のために働いていません。カラー画像を使用しましたが、エラーが発生しました:InvalidArgumentError:input_2:0がフィードとフェッチの両方をされています。
Vaibhav K

5

送信元:https : //github.com/philipperemy/keras-visualize-activations/blob/master/read_activations.py

import keras.backend as K

def get_activations(model, model_inputs, print_shape_only=False, layer_name=None):
    print('----- activations -----')
    activations = []
    inp = model.input

    model_multi_inputs_cond = True
    if not isinstance(inp, list):
        # only one input! let's wrap it in a list.
        inp = [inp]
        model_multi_inputs_cond = False

    outputs = [layer.output for layer in model.layers if
               layer.name == layer_name or layer_name is None]  # all layer outputs

    funcs = [K.function(inp + [K.learning_phase()], [out]) for out in outputs]  # evaluation functions

    if model_multi_inputs_cond:
        list_inputs = []
        list_inputs.extend(model_inputs)
        list_inputs.append(0.)
    else:
        list_inputs = [model_inputs, 0.]

    # Learning phase. 0 = Test mode (no dropout or batch normalization)
    # layer_outputs = [func([model_inputs, 0.])[0] for func in funcs]
    layer_outputs = [func(list_inputs)[0] for func in funcs]
    for layer_activations in layer_outputs:
        activations.append(layer_activations)
        if print_shape_only:
            print(layer_activations.shape)
        else:
            print(layer_activations)
    return activations

リンクは非推奨です。
Saeed


5

@mathtickのコメントで言及された問題を修正するために、@ indraforyouの回答にコメントとしてこれをコメントとして追加したかった(ただし、十分な担当者はいない)。InvalidArgumentError: input_X:Y is both fed and fetched.例外を回避するには、行outputs = [layer.output for layer in model.layers]outputs = [layer.output for layer in model.layers][1:]に置き換えます。つまり、

indraforyouの最小限の実例を適用する:

from keras import backend as K 
inp = model.input                                           # input placeholder
outputs = [layer.output for layer in model.layers][1:]        # all layer outputs except first (input) layer
functor = K.function([inp, K.learning_phase()], outputs )   # evaluation function

# Testing
test = np.random.random(input_shape)[np.newaxis,...]
layer_outs = functor([test, 1.])
print layer_outs

PS私のような試みoutputs = [layer.output for layer in model.layers[1:]]はうまくいきませんでした。


1
それは正確ではありません。これは、入力レイヤーが最初に定義されている場合のみです。
Mpizos Dimitris

おかげで、これは私にとってはうまくいきました。Mpizosのコメントに基づいて、理由を理解したことを確認したいと思います。私のモデルは3層(単語の埋め込み-BiLSTM-CRF)なので、層[0]を除外する必要があったので、埋め込みだけで、アクティブ化するべきではありませんよね?
KMunro

@MpizosDimitrisはい、それは正しいですが、@ indraforyouによって提供された例(私が修正しました)では、これが事実でした。@KMunro私が正しく理解している場合、最初のレイヤーの出力を気にしない理由は、それが単にテンソル形式でそれ自体を埋め込む単語である単語埋め込みの出力であるからです(これは単にkerasモデルの「ネットワーク」部分への入力)。単語の埋め込みレイヤーは、ここで提供されている例の入力レイヤーに相当します。
カムカム

3

あなたが持っていると仮定します:

1- Keras事前トレーニング済みmodel

2- x画像または画像のセットとして入力します。画像の解像度は、入力レイヤーの寸法と互換性がある必要があります。たとえば、80 * 80 * 3、3チャネル(RGB)画像のです。

3- layerアクティベーションを取得する出力の名前。たとえば、「flatten_2」レイヤー。これはlayer_names変数に含める必要があり、指定されたのレイヤーの名前を表しmodelます。

4- batch_sizeはオプションの引数です。

次にget_activation、関数を簡単に使用layerして、特定の入力xおよび事前トレーニングされた出力のアクティブ化を取得できますmodel

import six
import numpy as np
import keras.backend as k
from numpy import float32
def get_activations(x, model, layer, batch_size=128):
"""
Return the output of the specified layer for input `x`. `layer` is specified by layer index (between 0 and
`nb_layers - 1`) or by name. The number of layers can be determined by counting the results returned by
calling `layer_names`.
:param x: Input for computing the activations.
:type x: `np.ndarray`. Example: x.shape = (80, 80, 3)
:param model: pre-trained Keras model. Including weights.
:type model: keras.engine.sequential.Sequential. Example: model.input_shape = (None, 80, 80, 3)
:param layer: Layer for computing the activations
:type layer: `int` or `str`. Example: layer = 'flatten_2'
:param batch_size: Size of batches.
:type batch_size: `int`
:return: The output of `layer`, where the first dimension is the batch size corresponding to `x`.
:rtype: `np.ndarray`. Example: activations.shape = (1, 2000)
"""

    layer_names = [layer.name for layer in model.layers]
    if isinstance(layer, six.string_types):
        if layer not in layer_names:
            raise ValueError('Layer name %s is not part of the graph.' % layer)
        layer_name = layer
    elif isinstance(layer, int):
        if layer < 0 or layer >= len(layer_names):
            raise ValueError('Layer index %d is outside of range (0 to %d included).'
                             % (layer, len(layer_names) - 1))
        layer_name = layer_names[layer]
    else:
        raise TypeError('Layer must be of type `str` or `int`.')

    layer_output = model.get_layer(layer_name).output
    layer_input = model.input
    output_func = k.function([layer_input], [layer_output])

    # Apply preprocessing
    if x.shape == k.int_shape(model.input)[1:]:
        x_preproc = np.expand_dims(x, 0)
    else:
        x_preproc = x
    assert len(x_preproc.shape) == 4

    # Determine shape of expected output and prepare array
    output_shape = output_func([x_preproc[0][None, ...]])[0].shape
    activations = np.zeros((x_preproc.shape[0],) + output_shape[1:], dtype=float32)

    # Get activations with batching
    for batch_index in range(int(np.ceil(x_preproc.shape[0] / float(batch_size)))):
        begin, end = batch_index * batch_size, min((batch_index + 1) * batch_size, x_preproc.shape[0])
        activations[begin:end] = output_func([x_preproc[begin:end]])[0]

    return activations

2

次のいずれかの場合:

  • エラー: InvalidArgumentError: input_X:Y is both fed and fetched
  • 複数入力の場合

次の変更を行う必要があります。

  • outputs変数の入力レイヤーにフィルターを追加
  • functorsループの小さな変更

最小の例:

from keras.engine.input_layer import InputLayer
inp = model.input
outputs = [layer.output for layer in model.layers if not isinstance(layer, InputLayer)]
functors = [K.function(inp + [K.learning_phase()], [x]) for x in outputs]
layer_outputs = [fun([x1, x2, xn, 1]) for fun in functors]

はどういう意味[x1, x2, xn, 1]ですか?私のx1は定義されていません。そこで定義されているものを理解したいと思います。
HashRocketSyntax

@HashRocketSyntax x1x2モデルの入力です。前述のように、モデルに2つの入力がある場合。
Mpizos Dimitris

1

まあ、他の答えは非常に完全ですが、形状を「取得」するのではなく、「見る」ための非常に基本的な方法があります。

ただmodel.summary()。すべてのレイヤーとその出力形状を印刷します。「なし」の値は可変ディメンションを示し、最初のディメンションはバッチサイズになります。


これは、レイヤーではなく、レイヤーの出力(ベースレイヤーへの指定の入力)に関するものです。
mathtick
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.