Keras, her katmanın çıktısı nasıl alınır?


166

CNN ile bir ikili sınıflandırma modeli eğittim ve işte kodum

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

Ve burada, her katmanın çıktısını TensorFlow gibi almak istiyorum, bunu nasıl yapabilirim?

Yanıtlar:


193

Aşağıdakileri kullanarak herhangi bir katmanın çıktılarını kolayca alabilirsiniz: model.layers[index].output

Tüm katmanlar için şunu kullanın:

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

Not: Bırakma kullanımını taklit etmek learning_phaseolarak 1.içinde layer_outsaksi kullanımda0.

Düzenleme: (yorumlara göre)

K.function daha sonra girdi verilen sembolik grafikten çıktı almak için kullanılan ano / tensorflow tensör fonksiyonlarını oluşturur.

Şimdi K.learning_phase()Bırakma / Batchnomalization gibi birçok Keras katmanları eğitim ve test süresi boyunca değişim davranışına bağımlı olarak girdi olarak gereklidir.

Dolayısıyla, kodunuzdaki bırakma katmanını kaldırırsanız, şunları kullanabilirsiniz:

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

Düzenleme 2: Daha optimize edilmiş

Önceki cevabın, her işlev değerlendirmesi için verilerin CPU-> GPU belleğine aktarılacağı ve aynı zamanda tensör hesaplamalarının üst üste alt katmanlar için yapılması gerektiği kadar optimize edilmediğini fark ettim.

Bunun yerine, birden fazla işleve ihtiyacınız olmadığı için bu çok daha iyi bir yoldur, ancak size tüm çıktıların listesini veren tek bir işlev:

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
efendim, cevabınız güzel, K.function([inp]+ [K.learning_phase()], [out])kodunuzda ne anlama geliyor?
GoingMyWay

Mükemmel cevap, np.random.random(input_shape)[np.newaxis,...]şu şekilde de yazılabilirnp.random.random(input_shape)[np.newaxis,:]
Tom

K.function nedir? GPU'ya (MPI?) nasıl geçer? sahnenin arkasında ne var? CUDA ile görüşmeler nasıl? kaynak kodu nerede?
Stav Bodik

3
@StavBodik Modeli kullanılarak işlevini tahmin oluşturur K.function burada ve de kullanımlarını o tahmin döngü tahmin burada . Toplu iş boyutu üzerinden döngüleri tahmin edin (varsayılan olarak 32'ye ayarlanmazsa), ancak bu, GPU belleğindeki kısıtlamaları azaltmak içindir. Bu yüzden gözlemlemenin neden model.predictdaha hızlı olduğundan emin değilim .
indraforyou

1
Bunu alıyorum: InvalidArgumentError: S_input_39: 0 hem beslenir hem de getirilir. ... fikri olan var mı?
mathtick

151

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

Basit bir yol, ilgilendiğiniz katmanların çıktısını alacak yeni bir Model oluşturmaktır:

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)

Alternatif olarak, belirli bir girdi verilen belirli bir katmanın çıktısını döndürecek bir Keras işlevi oluşturabilirsiniz, örneğin:

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]

eğer sana iki ^ verebilseydim, Bu yol, bir sürü girdiniz olduğunda çok daha kullanışlıdır.
Dan Erez

Yukarıdaki kodunuzdan oldukça açık, ancak sadece anladığımı iki kez kontrol etmek için: mevcut bir modelden bir model oluşturduktan sonra (zaten eğitilmiş olduğunu varsayarak), yeni modelde set_weights çağırmaya gerek yoktur. Bu doğru mu?
JZ_42

layer_output = get_3rd_layer_output([X, 0])[0]ve arasındaki fark nedir? layer_output = get_3rd_layer_output([X, 1])[0]Dokümanlar tren modu ve test modundan bahsediyor
Jason

pardon, bu modelin tam olarak ne yaptığını bana açıklayabilir misin? Onu da eğitmen gerekiyor mu? Onun için herhangi bir şema hayal edemiyorum. Başka bir modelin girdi katmanını eklediniz, ardından diğer modelin rastgele bir ara katmanını çıktı olarak eklediniz ve girdileri ona besliyorsunuz? Orijinal modeli beslemek ve içindeki herhangi bir ara katmana doğrudan erişim sağlamak yerine bunu neden yapalım? Neden bu ekstra garip modeli yarattın? Ve çıktıyı etkilemeyecek mi? öğrenmeye veya eğitim gerektirmeyecek mi, yoksa katman, orijinal modelden önceden eğitilmiş kendi ağırlıklarını getirmeyecek mi?
PedroD

20

Bu konudaki tüm iyi cevaplara dayanarak, her katmanın çıktısını almak için bir kitaplık yazdım. Tüm karmaşıklığı özetler ve olabildiğince kullanıcı dostu olacak şekilde tasarlanmıştır:

https://github.com/philipperemy/keract

Neredeyse tüm uç durumları ele alıyor

Umarım yardımcı olur!


9

Aşağıdakiler bana çok basit görünüyor:

model.layers[idx].output

Yukarıda bir tensör nesnesi vardır, böylece bir tensör nesnesine uygulanabilen işlemleri kullanarak onu değiştirebilirsiniz.

Örneğin şekli almak için model.layers[idx].output.get_shape()

idx katmanın indeksidir ve onu buradan bulabilirsiniz model.summary()


1
Bu cevabın nesi var? Neden bu en iyi cevap olarak oylanmıyor?
Black Jack 21

2
Bir veri çerçevesi değil, bir tensör nesnesi döndürür. tf nesneleriyle çalışmak garip.
HashRocketSyntax

8

Bu işlevi kendim için (Jupyter'de) yazdım ve indraforyou'nun cevabından esinlenildi . Tüm katman çıktılarını otomatik olarak çizecektir. Resimleriniz, 1'in 1 kanalı temsil ettiği bir (x, y, 1) şeklinde olmalıdır. Sen sadece plot_layer_outputs (...) çağırırsın.

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

Ya modelin birkaç girdisi varsa? Girişleri nasıl belirlersiniz?
Antonio Sesto

Bu satırda: layer_outputs_list = [op ([test_image, 1.]). 1. 0 olması gerekir mi? Görünüşe göre 1 eğitim ve 0 test anlamına mı geliyor? Değil mi?
Kongsea

Bu benim için çalışmıyor. Renkli bir resim kullandım ve bu bana hata veriyor: InvalidArgumentError: input_2: 0 hem beslendi hem de alındı.
Vaibhav K

6

Gönderen: 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

Bağlantı kullanımdan kaldırıldı.
Saeed

5

Bunu @ mathtick'in yorumunda bahsedilen sorunu düzeltmek için @ indraforyou'nun cevabına bir yorum olarak eklemek istedim (ancak yeterince yüksek rep. Önlemek için InvalidArgumentError: input_X:Y is both fed and fetched.istisna sadece çizgiyi değiştirmek outputs = [layer.output for layer in model.layers]ile outputs = [layer.output for layer in model.layers][1:], yani

indraforyou'nun minimal çalışma örneğini uyarlamak:

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:]]işe yaramadı gibi şeyleri deneme girişimlerim .


1
bu tam olarak doğru değil. Bu yalnızca giriş katmanı ilk tanımlıysa geçerlidir.
Mpizos Dimitris

Teşekkürler, bu benim için çalıştı ve sadece Mpizos'un yorumuna dayanarak nedenini anladığımı kontrol etmek istiyorum: modelim sadece 3 katmandır (kelime yerleştirmeleri - BiLSTM - CRF), bu yüzden sanırım [0] katmanını hariç tutmak zorunda kaldım çünkü sadece gömmeler ve bir aktivasyon olmamalı, değil mi?
KMunro

@MpizosDimitris evet bu doğru, ancak @indraforyou tarafından sağlanan örnekte (benim düzeltiyordum) durum buydu. @KMunro eğer doğru anlıyorsam, o zaman ilk katmanın çıktısını önemsememenizin nedeni, bunun sadece kendisini tensör formuna yerleştiren kelime olan gömme kelimesinin çıktısı olmasıdır (ki bu sadece kerasmodelinizin "ağ" kısmına giriş ). Kelime yerleştirme katmanınız, burada verilen örnekteki giriş katmanına eşdeğerdir.
KamKam

3

Sahip olduğunuzu varsayarsak:

1- Keras önceden eğitilmiş model.

2- xGörüntü veya görüntü seti olarak girin . Görüntünün çözünürlüğü, giriş katmanının boyutuyla uyumlu olmalıdır. Örneğin 3 kanallı (RGB) görüntü için 80 * 80 * 3 .

3- layerAktivasyonu almak için çıktının adı . Örneğin, "flatten_2" katmanı. Bu, layer_namesdeğişkene dahil edilmelidir , verilen katmanların adını temsil eder model.

4- batch_sizeisteğe bağlı bir argümandır.

Ardından, belirli bir giriş get_activationiçin çıkışın etkinleştirilmesini ve önceden eğitilmiş olmasını sağlamak için işlevi kolayca kullanabilirsiniz :layerxmodel

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

Aşağıdaki durumlardan birine sahipseniz:

  • hata: InvalidArgumentError: input_X:Y is both fed and fetched
  • çoklu giriş durumu

Aşağıdaki değişiklikleri yapmanız gerekir:

  • outputsdeğişkendeki giriş katmanları için filtre ekleme
  • üzerinde minnor değişim functorsdöngüsü

Minimum örnek:

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]

İle kastedilen nedir [x1, x2, xn, 1]? X1'im tanımlı değil ve orada neyi tanımladığınızı anlamak istiyorum.
HashRocketSyntax

@HashRocketSyntax x1ve x2modelin girdileridir. Belirtildiği gibi modelinizde 2 girişiniz olması durumunda.
Mpizos Dimitris

0

Pekala, diğer cevaplar çok eksiksiz, ancak şekilleri "elde etmenin" değil "görmenin" çok basit bir yolu var.

Sadece bir model.summary(). Tüm katmanları ve çıktı şekillerini yazdıracaktır. "Yok" değerleri, değişken boyutları gösterecek ve ilk boyut, parti boyutu olacaktır.


Bu, katmanın çıktısı (temel katmana verilen girdiler) ile ilgilidir.
mathtick
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.