Keras, Bagaimana cara mendapatkan output dari setiap layer?


155

Saya telah melatih model klasifikasi biner dengan CNN, dan ini kode saya

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

Dan di sini, saya ingin mendapatkan output dari setiap layer seperti TensorFlow, bagaimana saya bisa melakukan itu?

Jawaban:


182

Anda dapat dengan mudah mendapatkan output dari lapisan apa pun dengan menggunakan: model.layers[index].output

Untuk semua lapisan gunakan ini:

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

Catatan: Untuk mensimulasikan Dropout digunakan learning_phasesebagai 1.di layer_outssebaliknya digunakan0.

Edit: (berdasarkan komentar)

K.function menciptakan theano / tensorflow fungsi tensor yang kemudian digunakan untuk mendapatkan output dari grafik simbolik yang diberikan input.

Sekarang K.learning_phase()diperlukan sebagai input karena banyak lapisan Keras seperti Dropout / Batchnomalization bergantung padanya untuk mengubah perilaku selama pelatihan dan waktu pengujian.

Jadi, jika Anda menghapus lapisan dropout dalam kode Anda, Anda dapat menggunakan:

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

Sunting 2: Lebih dioptimalkan

Saya baru menyadari bahwa jawaban sebelumnya bukanlah yang dioptimalkan karena untuk setiap evaluasi fungsi data akan ditransfer CPU-> memori GPU dan juga perhitungan tensor perlu dilakukan untuk lapisan bawah over-n-over.

Alih-alih, ini adalah cara yang jauh lebih baik karena Anda tidak memerlukan banyak fungsi tetapi satu fungsi memberi Anda daftar semua output:

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
Pak, jawaban Anda baik, apa K.function([inp]+ [K.learning_phase()], [out])artinya dalam kode Anda?
GoingMyWay

Jawaban yang sangat bagus, np.random.random(input_shape)[np.newaxis,...]dapat juga ditulis sebagainp.random.random(input_shape)[np.newaxis,:]
Tom

Apa fungsi K.? bagaimana cara diteruskan ke GPU (MPI?)? apa yang ada di belakang layar? Bagaimana cara berbicara dengan CUDA? di mana kode sumber?
Stav Bodik

3
@StavBodik Model membangun fungsi prediksi menggunakan di K.function sini , dan memprediksi menggunakannya dalam loop prediksi di sini . Memprediksi loop di atas ukuran batch (jika tidak diatur ke 32) tapi itu untuk mengurangi kendala pada memori GPU. Jadi saya tidak yakin mengapa Anda mengamati model.predictlebih cepat.
indraforyou

1
Saya mendapatkan ini: InvalidArgumentError: S_input_39: 0 diumpankan dan diambil. ... ada yang punya ide?
mathtick

138

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

Salah satu cara sederhana adalah membuat Model baru yang akan menampilkan lapisan yang Anda minati:

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)

Atau, Anda dapat membangun fungsi Keras yang akan mengembalikan output dari lapisan tertentu yang diberi input tertentu, misalnya:

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]

jika saya bisa, saya akan memberi Anda dua ^, Cara ini hanya sangaaaat jauh lebih nyaman ketika Anda memiliki banyak input.
Dan Erez

Cukup jelas dari kode Anda di atas, tetapi hanya untuk mengecek pemahaman saya: setelah membuat model dari model yang sudah ada (anggap sudah dilatih), tidak perlu memanggil set_weights pada model baru. Apakah itu benar?
JZ

apa perbedaan antara layer_output = get_3rd_layer_output([X, 0])[0]dan layer_output = get_3rd_layer_output([X, 1])[0]Dokumen menyebutkan mode kereta dan mode uji
Jason

maaf, bisakah Anda menjelaskan kepada saya apa yang sebenarnya dilakukan model ini? Apakah Anda harus melatihnya juga? Saya tidak bisa membayangkan diagram untuk itu. Anda menambahkan lapisan input dari model lain, lalu menambahkan lapisan perantara acak dari model lain sebagai output, dan mengumpankan input ke dalamnya? Mengapa ini bukannya memberi makan model asli dan mendapatkan akses langsung ke lapisan perantara mana pun di dalamnya? Mengapa membuat model ekstra aneh ini? Dan apakah itu tidak akan mempengaruhi output? bukankah itu mencoba untuk belajar atau membutuhkan pelatihan, atau lapisan membawa bobot sendiri yang sudah dilatih dari model asli?
PedroD

19

Berdasarkan semua jawaban yang baik dari utas ini, saya menulis perpustakaan untuk mengambil output dari setiap lapisan. Ini mengabstraksi semua kerumitan dan telah dirancang agar seramah mungkin:

https://github.com/philipperemy/keract

Ini menangani hampir semua kasus tepi

Semoga ini bisa membantu!


8

Berikut ini terlihat sangat sederhana bagi saya:

model.layers[idx].output

Di atas adalah objek tensor, sehingga Anda dapat memodifikasinya menggunakan operasi yang dapat diterapkan ke objek tensor.

Misalnya, untuk mendapatkan bentuk model.layers[idx].output.get_shape()

idx adalah indeks dari layer dan Anda dapat menemukannya dari model.summary()


1
Apa yang salah dengan jawaban ini? Mengapa ini tidak dipilih sebagai jawaban teratas?
Black Jack 21

1
Ini mengembalikan objek tensor, bukan dataframe. Jika benda itu aneh untuk dikerjakan.
HashRocketSyntax

7

Saya menulis fungsi ini untuk diri saya sendiri (di Jupyter) dan terinspirasi oleh jawaban indraforyou . Ini akan memplot semua output layer secara otomatis. Gambar Anda harus memiliki bentuk (x, y, 1) di mana 1 berarti 1 saluran. Anda cukup panggil plot_layer_outputs (...) untuk plot.

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

Bagaimana jika model memiliki beberapa input? Bagaimana Anda menentukan input?
Antonio Sesto

Di baris ini: layer_outputs_list = [op ([test_image, 1.]). Apakah 1. harus 0? Tampaknya 1 singkatan untuk pelatihan dan 0 singkatan untuk pengujian? Bukan?
Kongsea

Ini tidak bekerja untuk saya. Saya telah menggunakan gambar berwarna dan itu memberi saya kesalahan: InvalidArgumentError: input_2: 0 keduanya diumpankan dan diambil.
Vaibhav K

5

Dari: 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

Tautan sudah usang.
Saeed


5

Ingin menambahkan ini sebagai komentar (tetapi tidak memiliki perwakilan cukup tinggi) untuk jawaban @ indraforyou untuk memperbaiki masalah yang disebutkan dalam komentar @ mathtick. Untuk menghindari InvalidArgumentError: input_X:Y is both fed and fetched.pengecualian, cukup ganti baris outputs = [layer.output for layer in model.layers]dengan outputs = [layer.output for layer in model.layers][1:], yaitu

mengadaptasi contoh kerja minimal 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 upaya saya mencoba hal-hal seperti outputs = [layer.output for layer in model.layers[1:]]tidak berhasil.


1
itu tidak sepenuhnya benar. Ini hanya jika lapisan input adalah yang pertama ditentukan.
Mpizos Dimitris

Terima kasih, ini bekerja untuk saya dan saya hanya ingin memeriksa saya mengerti mengapa, berdasarkan komentar Mpizos ': model saya hanya 3 layer (kata embeddings - BiLSTM - CRF), jadi saya kira saya harus mengecualikan layer [0] karena ini hanya embeddings dan tidak harus memiliki aktivasi, kan?
KMunro

@MpizosDimitris ya itu benar, tetapi dalam contoh yang diberikan oleh @indraforyou (yang saya ubah), inilah masalahnya. @Kunro jika saya mengerti dengan benar, maka alasan Anda tidak peduli tentang output Anda dari lapisan pertama adalah karena itu hanyalah output dari kata embedding yang hanya kata embedding sendiri dalam bentuk tensor (yang hanya merupakan masukan ke bagian "jaringan" dari kerasmodel Anda ). Lapisan embeddings kata Anda setara dengan layer input pada contoh yang diberikan di sini.
KamKam

3

Dengan asumsi Anda memiliki:

1- Keras pra-terlatih model.

2- Input xsebagai gambar atau set gambar. Resolusi gambar harus kompatibel dengan dimensi lapisan input. Misalnya 80 * 80 * 3 untuk gambar 3-saluran (RGB).

3- Nama output layeruntuk mendapatkan aktivasi. Misalnya, lapisan "flatten_2". Ini harus dimasukkan dalam layer_namesvariabel, mewakili nama lapisan yang diberikan model.

4- batch_sizeadalah argumen opsional.

Kemudian Anda dapat dengan mudah menggunakan get_activationfungsi untuk mendapatkan aktivasi output layeruntuk input yang diberikan xdan pra-dilatih 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

Jika Anda memiliki salah satu dari kasus berikut:

  • kesalahan: InvalidArgumentError: input_X:Y is both fed and fetched
  • kasus beberapa input

Anda perlu melakukan perubahan berikut:

  • tambahkan filter untuk input layer dalam outputsvariabel
  • perubahan minnor pada functorsloop

Contoh minimum:

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]

Apa yang dimaksud dengan [x1, x2, xn, 1]? X1 saya tidak didefinisikan dan saya ingin memahami apa yang Anda definisikan di sana.
HashRocketSyntax

@HashRocketSyntax x1dan x2merupakan input dari model. Seperti yang dinyatakan itu jika Anda mendapat 2 input pada model Anda.
Mpizos Dimitris

1

Yah, jawaban lain sangat lengkap, tetapi ada cara yang sangat mendasar untuk "melihat", bukan "mendapatkan" bentuk.

Lakukan saja model.summary(). Ini akan mencetak semua layer dan bentuk output mereka. Nilai "None" akan menunjukkan dimensi variabel, dan dimensi pertama adalah ukuran batch.


Ini adalah tentang output dari layer (diberikan input ke layer dasar) bukan layer.
mathtick
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.