Keras, วิธีรับเอาต์พุตของแต่ละเลเยอร์


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 tensor ซึ่งใช้ในภายหลังเพื่อรับเอาต์พุตจากกราฟสัญลักษณ์ที่กำหนดอินพุต

ตอนนี้K.learning_phase()จำเป็นต้องใช้อินพุตเป็นเลเยอร์ Keras หลายอย่างเช่น Dropout / Batchnomalization ขึ้นอยู่กับการเปลี่ยนแปลงพฤติกรรมในระหว่างการฝึกซ้อมและเวลาทดสอบ

ดังนั้นหากคุณลบชั้นออกกลางคันในรหัสของคุณคุณสามารถใช้:

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

คำตอบที่ยอดเยี่ยม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 ที่นี่และคาดการณ์การใช้งานในการทำนายห่วงนี่ การคาดการณ์จะวนลูปมากกว่าขนาดแบทช์ (หากไม่ได้ตั้งไว้มันจะมีค่าเริ่มต้นเป็น 32) แต่จะลดข้อ จำกัด ของหน่วยความจำ GPU ดังนั้นฉันไม่แน่ใจว่าทำไมคุณกำลังสังเกตmodel.predictได้เร็วขึ้น
indraforyou

1
กำลังได้รับสิ่งนี้: InvalidArgumentError: S_input_39: 0 ถูกป้อนและดึงข้อมูล ... ใครที่มีความคิด
mathtick

138

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

วิธีง่ายๆวิธีหนึ่งคือการสร้างแบบจำลองใหม่ที่จะแสดงเลเยอร์ที่คุณสนใจ:

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]

ถ้าฉันจะให้สองคุณได้วิธีนี้จะสะดวกกว่านี้มากเมื่อคุณมีอินพุต
Dan Erez

มันค่อนข้างชัดเจนจากโค้ดของคุณด้านบน แต่เพียงเพื่อตรวจสอบความเข้าใจของฉันอีกครั้ง: หลังจากสร้างแบบจำลองจากแบบจำลองที่มีอยู่แล้ว (สมมติว่าผ่านการฝึกอบรมมาแล้ว) ไม่จำเป็นต้องเรียก set_weights บนแบบจำลองใหม่ ถูกต้องไหม
JZ

อะไรคือความแตกต่างระหว่างlayer_output = get_3rd_layer_output([X, 0])[0]และlayer_output = get_3rd_layer_output([X, 1])[0]เอกสารพูดถึงโหมดรถไฟและโหมดทดสอบ
Jason

ขออภัยคุณช่วยอธิบายฉันว่ารุ่นนี้ทำอะไรได้บ้าง คุณต้องฝึกมันด้วยเหรอ? ฉันไม่สามารถจินตนาการไดอะแกรมใด ๆ คุณเพิ่มเลเยอร์อินพุตของโมเดลอื่นจากนั้นเพิ่มเลเยอร์ตัวกลางแบบสุ่มของโมเดลอื่นเป็นเอาต์พุตและป้อนฟีดเข้ากับมัน ทำไมทำเช่นนี้แทนที่จะป้อนรุ่นดั้งเดิมและเข้าถึงโดยตรงไปยังเลเยอร์ตัวกลางใด ๆ ทำไมต้องสร้างแบบจำลองที่แปลกพิเศษนี้ และจะไม่ส่งผลกระทบต่อเอาต์พุตหรือไม่ มันจะไม่พยายามเรียนรู้หรือต้องการการฝึกอบรมหรือไม่หรือเลเยอร์นำน้ำหนักของตนเองมาก่อนการฝึกจากแบบจำลองดั้งเดิม
PedroD

19

จากคำตอบที่ดีของกระทู้นี้ฉันเขียนไลบรารี่เพื่อดึงเอาท์พุทของแต่ละเลเยอร์ มันสรุปความซับซ้อนทั้งหมดและได้รับการออกแบบให้ใช้งานง่ายที่สุด:

https://github.com/philipperemy/keract

มันจัดการกรณีขอบเกือบทั้งหมด

หวังว่ามันจะช่วย!


8

ต่อไปนี้ดูเรียบง่ายสำหรับฉัน:

model.layers[idx].output

ด้านบนเป็นวัตถุเทนเซอร์ดังนั้นคุณสามารถแก้ไขโดยใช้การดำเนินการที่สามารถนำไปใช้กับวัตถุเทนเซอร์

ตัวอย่างเช่นเพื่อให้ได้รูปร่าง model.layers[idx].output.get_shape()

idx คือดัชนีของเลเยอร์และคุณสามารถค้นหาได้ model.summary()


1
เกิดอะไรขึ้นกับคำตอบนี้ ทำไม upvoted นี้ไม่เป็นคำตอบที่ดีที่สุด
แจ็คสีดำ 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

ในบรรทัดนี้: layer_outputs_list = [op ([test_image, 1. ]) 1. ต้องเป็น 0 หรือไม่ ดูเหมือนว่า 1 หมายถึงการฝึกอบรมและ 0 หมายถึงการทดสอบ? ไม่ใช่หรือ
Kongsea

มันไม่ทำงานสำหรับฉัน ฉันใช้ภาพสีและมันทำให้ฉันมีข้อผิดพลาด: 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

ต้องการเพิ่มสิ่งนี้เป็นความคิดเห็น (แต่ไม่มีตัวแทนที่สูงพอ) ในคำตอบของ @ indraforyou เพื่อแก้ไขสำหรับปัญหาที่กล่าวถึงในความคิดเห็นของ @ mathtick เพื่อหลีกเลี่ยง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

ป.ล. ความพยายามของฉันพยายามทำสิ่งต่าง ๆ เช่นoutputs = [layer.output for layer in model.layers[1:]]ไม่ทำงาน


1
ที่ไม่ถูกต้อง สิ่งนี้จะเกิดขึ้นถ้าเลเยอร์การป้อนข้อมูลเป็นครั้งแรกที่กำหนดไว้
Mpizos Dimitris

ขอบคุณสิ่งนี้ใช้ได้สำหรับฉันและฉันต้องการตรวจสอบว่าฉันเข้าใจว่าทำไมตามความคิดเห็นของ Mpizos: แบบจำลองของฉันมีเพียง 3 เลเยอร์ (คำว่า embeddings - BiLSTM - CRF) ดังนั้นฉันเดาว่าฉันต้องแยกเลเยอร์ [0] เพียงแค่ทำการแต่งงานและไม่ควรเปิดใช้งานใช่ไหม
KMunro

@MpizosDimitris ใช่ถูกต้อง แต่ในตัวอย่างที่ได้รับจาก @indraforyou (ซึ่งฉันแก้ไข) นี่เป็นกรณี @Kunun ถ้าฉันเข้าใจถูกต้องแล้วเหตุผลที่คุณไม่สนใจเกี่ยวกับผลลัพธ์ของเลเยอร์แรกก็เพราะมันเป็นเพียงแค่เอาท์พุทของคำที่ฝังซึ่งเป็นเพียงคำที่ฝังตัวในรูปแบบเทนเซอร์ (ซึ่งเป็นเพียง ป้อนไปยังส่วน "เครือข่าย" ของkerasแบบจำลองของคุณ) เลเยอร์คำปักของคุณเทียบเท่ากับเลเยอร์อินพุตในตัวอย่างที่ให้ไว้ที่นี่
KamKam

3

สมมติว่าคุณมี:

1- Keras ผ่านการฝึกอบรมmodelล่วงหน้า

2- ใส่xเป็นภาพหรือชุดของภาพ ความละเอียดของภาพควรเข้ากันได้กับขนาดของเลเยอร์อินพุต ตัวอย่างเช่น80 * 80 * 3สำหรับรูปภาพ 3 แชนเนล (RGB)

3- ชื่อของเอาต์พุตlayerเพื่อรับการเปิดใช้งาน ตัวอย่างเช่นเลเยอร์ "flatten_2" นี้ควรจะรวมอยู่ในตัวแปรแสดงชื่อของชั้นที่กำหนดlayer_namesmodel

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 x1และx2เป็นอินพุตของโมเดล ตามที่ระบุไว้เพราะในกรณีที่คุณมี 2 อินพุตในรูปแบบของคุณ
Mpizos Dimitris

1

คำตอบอื่น ๆ นั้นสมบูรณ์มาก แต่ก็มีวิธีการพื้นฐานที่จะ "เห็น" ไม่ใช่เพื่อ "รับ" รูปร่าง

model.summary()เพียงแค่ทำ มันจะพิมพ์เลเยอร์ทั้งหมดและรูปร่างของพวกเขาออก ค่า "ไม่มี" จะระบุขนาดของตัวแปรและส่วนแรกจะเป็นขนาดแบทช์


นี่เป็นเรื่องเกี่ยวกับผลลัพธ์ของเลเยอร์ (อินพุตที่กำหนดให้กับเลเยอร์ฐาน) ไม่ใช่เลเยอร์
mathtick
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.