Keras, wie bekomme ich die Ausgabe jeder Schicht?

154

Ich habe ein binäres Klassifizierungsmodell mit CNN trainiert und hier ist mein Code

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))

Und hier möchte ich die Ausgabe jeder Ebene genau wie TensorFlow erhalten. Wie kann ich das tun?

Ich gehe meinen Weg
quelle

Antworten:

181

Sie können die Ausgaben jeder Ebene einfach abrufen, indem Sie Folgendes verwenden: model.layers[index].output

Verwenden Sie für alle Ebenen Folgendes:

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

Hinweis: Um die Dropout-Verwendung learning_phasewie 1.bei einer layer_outsanderen Verwendung zu simulieren0.

Bearbeiten: (basierend auf Kommentaren)

K.function Erstellt die Theano- / Tensorflow-Tensorfunktionen, die später verwendet werden, um die Ausgabe aus dem symbolischen Diagramm bei gegebener Eingabe zu erhalten.

Jetzt K.learning_phase()ist eine Eingabe erforderlich, da viele Keras-Ebenen wie Dropout / Batchnomalization davon abhängen, um das Verhalten während des Trainings und der Testzeit zu ändern.

Wenn Sie also die Dropout-Ebene in Ihrem Code entfernen, können Sie einfach Folgendes verwenden:

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

Edit 2: Optimierter

Ich habe gerade festgestellt, dass die vorherige Antwort nicht so optimiert ist, da für jede Funktionsbewertung die Daten übertragen werden. CPU-> GPU-Speicher und auch die Tensorberechnungen müssen für die unteren Schichten über und über durchgeführt werden.

Stattdessen ist dies ein viel besserer Weg, da Sie nicht mehrere Funktionen benötigen, sondern eine einzige Funktion, die Ihnen die Liste aller Ausgaben liefert:

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
indraforyou
quelle
2
Sir, Ihre Antwort ist gut. Was K.function([inp]+ [K.learning_phase()], [out])bedeutet Ihr Code?
GoingMyWay
Ausgezeichnete Antwort, np.random.random(input_shape)[np.newaxis,...]kann auch geschrieben werden alsnp.random.random(input_shape)[np.newaxis,:]
Tom
Was ist K.Funktion? Wie wird es an die GPU (MPI?) weitergegeben? Was gibt es hinter den Kulissen? Wie ist es Gespräche mit CUDA? Wo ist der Quellcode?
Stav Bodik
3
@StavBodik Modell baut die Funktion vorhersagen , mit K.function hier und vorherzusagen , verwendet es in der vorherzusagen Schleife hier . Prognostizieren Sie Schleifen über die Stapelgröße (falls nicht standardmäßig 32 festgelegt), um die Einschränkungen des GPU-Speichers zu verringern. Ich bin mir also nicht sicher, warum Sie beobachten, model.predictist schneller.
Indraforyou
1
Ich erhalte Folgendes: InvalidArgumentError: S_input_39: 0 wird sowohl gespeist als auch abgerufen. ... jemand mit Ideen?
Mathtick
137

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

Eine einfache Möglichkeit besteht darin, ein neues Modell zu erstellen, das die Ebenen ausgibt, an denen Sie interessiert sind:

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)

Alternativ können Sie eine Keras-Funktion erstellen, die die Ausgabe einer bestimmten Ebene bei einer bestimmten Eingabe zurückgibt, z. B.:

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]
blauer Himmel
quelle
Wenn ich könnte, würde ich Ihnen zwei geben. Dieser Weg ist einfach sooooo viel bequemer, wenn Sie eine Reihe von Eingaben haben.
Dan Erez
Aus Ihrem obigen Code geht ziemlich klar hervor, aber nur um mein Verständnis zu überprüfen: Nachdem Sie ein Modell aus einem vorhandenen Modell erstellt haben (vorausgesetzt, es ist bereits trainiert), müssen Sie für das neue Modell nicht set_weights aufrufen. Ist das korrekt?
JZ
Was ist der Unterschied zwischen layer_output = get_3rd_layer_output([X, 0])[0]und layer_output = get_3rd_layer_output([X, 1])[0]Die Dokumente erwähnen Zugmodus und Testmodus
Jason
Entschuldigung, können Sie mir erklären, was genau dieses Modell macht? Musst du es auch trainieren? Ich kann mir kein Diagramm dazu vorstellen. Sie fügen die Eingabeebene eines anderen Modells hinzu, fügen dann eine zufällige Zwischenebene dieses anderen Modells als Ausgabe hinzu und geben Eingaben ein? Warum tun Sie dies, anstatt das Originalmodell zu füttern und direkten Zugriff auf eine Zwischenschicht zu erhalten? Warum dieses besonders seltsame Modell erstellen? Und wird es die Ausgabe nicht beeinflussen? Wird es nicht versuchen zu lernen oder Training zu erfordern, oder die Schicht bringt ihre eigenen Gewichte mit, die vom Originalmodell vorab trainiert wurden?
PedroD
19

Basierend auf all den guten Antworten dieses Threads habe ich eine Bibliothek geschrieben, um die Ausgabe jeder Ebene abzurufen. Es abstrahiert die gesamte Komplexität und wurde so benutzerfreundlich wie möglich gestaltet:

https://github.com/philipperemy/keract

Es behandelt fast alle Randfälle

Ich hoffe es hilft!

Philippe Remy
quelle
8

Folgendes sieht für mich sehr einfach aus:

model.layers[idx].output

Oben befindet sich ein Tensorobjekt, sodass Sie es mithilfe von Operationen ändern können, die auf ein Tensorobjekt angewendet werden können.

Zum Beispiel, um die Form zu bekommen model.layers[idx].output.get_shape()

idx ist der Index der Ebene und Sie können ihn von finden model.summary()

Teufel im Detail
quelle
1
Was ist los mit dieser Antwort? Warum ist dies nicht die beste Antwort?
Black Jack 21
1
Es gibt ein Tensorobjekt zurück, keinen Datenrahmen. Es ist seltsam, mit Objekten zu arbeiten.
HashRocketSyntax
7

Ich habe diese Funktion für mich selbst geschrieben (in Jupyter) und sie wurde von Indraforyous Antwort inspiriert . Alle Ebenenausgaben werden automatisch geplottet. Ihre Bilder müssen eine (x, y, 1) Form haben, wobei 1 für 1 Kanal steht. Sie rufen einfach plot_layer_outputs (...) auf, um zu zeichnen.

%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')
Miladiouss
quelle
Was ist, wenn das Modell mehrere Eingänge hat? Wie legen Sie die Eingaben fest?
Antonio Sesto
In dieser Zeile: layer_outputs_list = [op ([test_image, 1.]). Muss 1. 0 sein? Es scheint, 1 steht für Training und 0 steht für Testen? Ist nicht ist?
Kongsea
Das funktioniert bei mir nicht. Ich habe ein Farbbild verwendet und es gibt mir einen Fehler: InvalidArgumentError: input_2: 0 wird sowohl eingezogen als auch abgerufen.
Vaibhav K
5

Von: 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
Cannin
quelle
Link ist veraltet.
Saeed
5

Wollte dies als Kommentar (aber nicht hoch genug) zu @ indraforyous Antwort hinzufügen, um das in @ mathticks Kommentar erwähnte Problem zu beheben. Um die InvalidArgumentError: input_X:Y is both fed and fetched.Ausnahme zu vermeiden , ersetzen Sie einfach die Zeile outputs = [layer.output for layer in model.layers]durch outputs = [layer.output for layer in model.layers][1:], dh

Anpassen des minimalen Arbeitsbeispiels von 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 meine Versuche, Dinge auszuprobieren, wie outputs = [layer.output for layer in model.layers[1:]]sie nicht funktionierten.

KamKam
quelle
1
das ist nicht genau richtig. Dies ist nur möglich, wenn die Eingabeebene die erste ist, die definiert wurde.
Mpizos Dimitris
Danke, das hat bei mir funktioniert und ich möchte nur überprüfen, ob ich verstehe, warum, basierend auf Mpizos 'Kommentar: Mein Modell besteht nur aus 3 Ebenen (Worteinbettungen - BiLSTM - CRF), also musste ich wohl die Ebene [0] ausschließen, da dies der Fall ist nur Einbettungen und sollte keine Aktivierung haben, oder?
KMunro
@MpizosDimitris Ja, das ist richtig, aber in dem Beispiel von @indraforyou (das ich geändert habe) war dies der Fall. @KMunro Wenn ich das richtig verstehe, ist der Grund, warum Sie sich nicht für Ihre Ausgabe der ersten Ebene interessieren, der, dass es einfach die Ausgabe der Worteinbettung ist, die nur das Wort ist, das sich selbst in Tensorform einbettet (was nur die ist Eingabe in den "Netzwerk" -Teil Ihres kerasModells). Ihre Worteinbettungsebene entspricht der Eingabeebene im hier angegebenen Beispiel.
KamKam
3

Vorausgesetzt, Sie haben:

1- Keras vorab trainiert model.

2- Eingabe xals Bild oder Bildsatz. Die Auflösung des Bildes sollte mit der Dimension der Eingabeebene kompatibel sein. Zum Beispiel 80 * 80 * 3 für 3-Kanal-Bilder (RGB).

3- Der Name des Ausgangs layer, um die Aktivierung zu erhalten. Zum Beispiel die Ebene "flatten_2". Dies sollte in der layer_namesVariablen enthalten sein, repräsentiert den Namen der Ebenen der angegebenen model.

4- batch_sizeist ein optionales Argument.

Dann können Sie einfach die get_activationFunktion verwenden, um die Aktivierung des Ausgangs layerfür einen bestimmten Eingang zu erhalten xund vorab zu trainieren 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
imanzabet
quelle
2

Falls Sie einen der folgenden Fälle haben:

  • Error: InvalidArgumentError: input_X:Y is both fed and fetched
  • Fall von mehreren Eingängen

Sie müssen die folgenden Änderungen vornehmen:

  • Filter für Eingabe-Layer in outputsVariable hinzufügen
  • minnor change on functorsloop

Minimales Beispiel:

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]
Mpizos Dimitris
quelle
Was ist damit gemeint [x1, x2, xn, 1]? Mein x1 ist nicht definiert und ich möchte verstehen, was Sie dort definieren.
HashRocketSyntax
@ HashRocketSyntax x1und x2sind die Eingaben des Modells. Wie bereits erwähnt, haben Sie 2 Eingaben für Ihr Modell.
Mpizos Dimitris
1

Nun, andere Antworten sind sehr vollständig, aber es gibt eine sehr grundlegende Möglichkeit, die Formen zu "sehen" und nicht zu "bekommen".

Mach einfach eine model.summary(). Es werden alle Ebenen und ihre Ausgabeformen gedruckt. "Keine" -Werte geben variable Dimensionen an, und die erste Dimension ist die Stapelgröße.

Daniel Möller
quelle
Hier geht es um die Ausgabe der Ebene (gegebene Eingaben in die Basisschicht), nicht um die Ebene.
Mathtick