web-dev-qa-db-fra.com

Keras, Comment obtenir la sortie de chaque couche?

J'ai formé un modèle de classification binaire avec CNN, et voici mon 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))

Et ici, je veux obtenir la sortie de chaque couche exactement comme TensorFlow, comment puis-je faire cela?

100
GoingMyWay

Vous pouvez facilement obtenir les résultats de n'importe quelle couche en utilisant: model.layers[index].output

Pour toutes les couches, utilisez ceci:

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

Remarque: pour simuler un abandon, utilisez learning_phase comme 1. dans layer_outs sinon utilisez 0..

Edit: (basé sur les commentaires)

K.function crée les fonctions tensioanean/tensorflow qui sont ensuite utilisées pour obtenir la sortie du graphe symbolique donné en entrée.

Maintenant, K.learning_phase() est requis en tant qu'entrée, car de nombreuses couches de Keras telles que Dropout/Batchnomalization en dépendent pour changer le comportement pendant la formation et la période de test.

Donc, si vous supprimez la couche de suppression dans votre code, vous pouvez simplement utiliser:

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: Plus optimisé

Je viens de me rendre compte que la réponse précédente n’est pas optimisée, car pour chaque évaluation de fonction, les données seront transférées CPU-> mémoire GPU et les calculs de tenseur doivent également être effectués pour les couches inférieures sur-n-over.

Au lieu de cela, c'est une bien meilleure façon, car vous n'avez pas besoin de plusieurs fonctions, mais d'une seule fonction vous donnant la liste de toutes les sorties:

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
133
indraforyou

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

Un moyen simple consiste à créer un nouveau modèle qui générera les couches qui vous intéressent:

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)

Vous pouvez également créer une fonction Keras qui renverra la sortie d'une couche donnée à partir d'une entrée donnée, par exemple:

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]
88
blue-sky

J'ai écrit cette fonction pour moi-même (en Jupyter) et elle s’inspire de la réponse de indraforyo . Il va tracer toutes les sorties de couche automatiquement. Vos images doivent avoir une forme (x, y, 1) où 1 représente 1 canal. Vous appelez simplement plot_layer_outputs (...) pour tracer.

%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')
6
Miladiouss

Suivre me semble très simple:

model.layers[idx].output

Ci-dessus est un objet tenseur, vous pouvez donc le modifier à l'aide d'opérations pouvant être appliquées à un objet tenseur.

Par exemple, pour obtenir la forme model.layers[idx].output.get_shape()

idx est l'index de la couche et vous pouvez le trouver dans model.summary()

5

Sur la base de toutes les bonnes réponses de ce fil, j'ai écrit une bibliothèque pour récupérer le résultat de chaque couche. Il en résume toute la complexité et a été conçu pour être le plus convivial possible:

https://github.com/philipperemy/keract

Il gère presque tous les cas Edge

J'espère que ça aide!

4
Philippe Remy

Voulait ajouter ceci en tant que commentaire (mais ne pas avoir une assez haute réputation) pour la réponse de @ indraforyou à corriger pour le problème mentionné dans le commentaire de @ mathtick. Pour éviter l'exception InvalidArgumentError: input_X:Y is both fed and fetched., remplacez simplement la ligne outputs = [layer.output for layer in model.layers] par outputs = [layer.output for layer in model.layers][1:], c'est-à-dire.

adapter l'exemple de travail minimal d'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

p.s. mes tentatives d'essayer des choses telles que outputs = [layer.output for layer in model.layers[1:]] n'ont pas fonctionné.

3
KamKam

De: 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
3
cannin

Eh bien, les autres réponses sont très complètes, mais il existe un moyen très simple de "voir", de "ne pas" obtenir les formes.

Il suffit de faire un model.summary(). Il imprimera tous les calques et leurs formes de sortie. Les valeurs "Aucune" indiquent des dimensions variables et la première dimension correspond à la taille du lot.

2
Daniel Möller

En supposant que vous ayez:

1- Keras pré-formés model.

2- Entrez x sous forme d'image ou de jeu d'images. La résolution de l'image doit être compatible avec la dimension du calque d'entrée. Par exemple, 80 * 80 * pour une image à 3 canaux (RVB).

3- Le nom de la sortie layer pour obtenir l'activation. Par exemple, couche "flatten_2". Ceci doit être inclus dans la variable layer_names, représente le nom des couches de la variable model donnée.

4- batch_size est un argument optionnel.

Ensuite, vous pouvez facilement utiliser la fonction get_activation pour obtenir l'activation de la sortie layer pour une entrée donnée x et préformé 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
0
imanzabet