Máy ảnh, Làm thế nào để có được đầu ra của mỗi lớp?


155

Tôi đã đào tạo mô hình phân loại nhị phân với CNN và đây là mã của tôi

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

Và ở đây, tôi muốn có được đầu ra của mỗi lớp giống như TensorFlow, làm thế nào tôi có thể làm điều đó?

Câu trả lời:


182

Bạn có thể dễ dàng nhận được kết quả đầu ra của bất kỳ lớp nào bằng cách sử dụng: model.layers[index].output

Đối với tất cả các lớp sử dụng này:

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

Lưu ý: Để mô phỏng Dropout sử dụng learning_phasenhư 1.trong layer_outstrường hợp sử dụng0.

Chỉnh sửa: (dựa trên ý kiến)

K.function tạo các hàm tenxơ theano / tenorflow mà sau này được sử dụng để lấy đầu ra từ biểu đồ tượng trưng cho đầu vào.

Bây giờ K.learning_phase()được yêu cầu làm đầu vào vì nhiều lớp Keras như Dropout / Batchnomalization phụ thuộc vào nó để thay đổi hành vi trong thời gian đào tạo và kiểm tra.

Vì vậy, nếu bạn loại bỏ lớp bỏ trong mã của mình, bạn chỉ cần sử dụng:

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

Chỉnh sửa 2: Tối ưu hóa hơn

Tôi chỉ nhận ra rằng câu trả lời trước đó không được tối ưu hóa vì với mỗi lần đánh giá chức năng, dữ liệu sẽ được chuyển CPU-> bộ nhớ GPU và cũng cần phải thực hiện các phép tính tenor cho các lớp thấp hơn.

Thay vào đó, đây là cách tốt hơn nhiều vì bạn không cần nhiều chức năng nhưng một chức năng duy nhất cung cấp cho bạn danh sách tất cả các kết quả đầu ra:

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
Thưa ông, câu trả lời của bạn là tốt, K.function([inp]+ [K.learning_phase()], [out])có nghĩa là gì trong mã của bạn?
Đi MYWay

Câu trả lời tuyệt vời, np.random.random(input_shape)[np.newaxis,...]cũng có thể được viết lànp.random.random(input_shape)[np.newaxis,:]
Tom

Chức năng là gì? Làm thế nào để nó được chuyển qua GPU (MPI?)? Có gì đằng sau hậu trường? Làm thế nào là cuộc nói chuyện với CUDA? mã nguồn ở đâu?
Stav Bodik

3
Mô hình @StavBodik xây dựng hàm dự đoán bằng cách sử dụng K.function ở đây và dự đoán sử dụng nó trong vòng dự đoán ở đây . Dự đoán các vòng lặp trên kích thước lô (nếu không đặt mặc định là 32) nhưng đó là để giảm thiểu các ràng buộc trên bộ nhớ GPU. Vì vậy, tôi không chắc tại sao bạn quan sát model.predictlà nhanh hơn.
indraforyou

1
Đang nhận được điều này: UnlimitedArgumentError: S_input_39: 0 được cung cấp và tìm nạp. ... có ai có ý tưởng không?
mathtick 15/03/19

137

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

Một cách đơn giản là tạo một Mô hình mới sẽ xuất ra các lớp mà bạn quan tâm:

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)

Ngoài ra, bạn có thể xây dựng một hàm Keras sẽ trả về đầu ra của một lớp nhất định được cung cấp một đầu vào nhất định, ví dụ:

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]

Nếu tôi có thể cung cấp cho bạn hai ^, Cách này sẽ thuận tiện hơn nhiều khi bạn có một loạt các đầu vào.
Dan Erez

Nó khá rõ ràng từ mã của bạn ở trên nhưng chỉ cần kiểm tra lại sự hiểu biết của tôi: sau khi tạo một mô hình từ một mô hình hiện có (giả sử nó đã được đào tạo), không cần phải gọi set_weights trên mô hình mới. Đúng không?
JZ

sự khác biệt giữa layer_output = get_3rd_layer_output([X, 0])[0]layer_output = get_3rd_layer_output([X, 1])[0]tài liệu đề cập đến chế độ tàu và chế độ thử nghiệm
Jason

xin lỗi, bạn có thể giải thích cho tôi mô hình này làm gì chính xác không? Bạn có phải đào tạo nó là tốt? Tôi không thể tưởng tượng bất kỳ sơ đồ cho nó. Bạn thêm lớp đầu vào của một mô hình khác, sau đó thêm một lớp trung gian ngẫu nhiên của mô hình khác đó làm đầu ra và cung cấp đầu vào cho nó? Tại sao làm điều này thay vì cho ăn mô hình ban đầu và có quyền truy cập trực tiếp vào bất kỳ lớp trung gian nào trong đó? Tại sao tạo ra mô hình kỳ lạ thêm này? Và nó sẽ không ảnh hưởng đến đầu ra? Nó sẽ không cố gắng học hỏi hay yêu cầu đào tạo, hay lớp mang trọng lượng riêng được đào tạo từ mô hình ban đầu?
Pedro

19

Dựa trên tất cả các câu trả lời hay của chủ đề này, tôi đã viết một thư viện để tìm nạp đầu ra của mỗi lớp. Nó trừu tượng hóa tất cả sự phức tạp và đã được thiết kế để thân thiện với người dùng nhất có thể:

https://github.com/philipperemy/keract

Nó xử lý hầu hết các trường hợp cạnh

Hy vọng nó giúp!


8

Theo tôi có vẻ rất đơn giản:

model.layers[idx].output

Trên đây là một đối tượng tenor, vì vậy bạn có thể sửa đổi nó bằng các thao tác có thể được áp dụng cho một đối tượng tenor.

Ví dụ, để có được hình dạng model.layers[idx].output.get_shape()

idx là chỉ mục của lớp và bạn có thể tìm thấy nó từ model.summary()


1
Có gì sai với câu trả lời này? Tại sao điều này không được nêu lên là câu trả lời hàng đầu?
Black Jack 21

1
Nó trả về một đối tượng tenor, không phải là một khung dữ liệu. đối tượng tf là lạ để làm việc với.
HashRocketSyntax

7

Tôi đã viết chức năng này cho chính mình (trong Jupyter) và nó được lấy cảm hứng từ câu trả lời của indraforyou . Nó sẽ vẽ tất cả các đầu ra lớp tự động. Hình ảnh của bạn phải có hình dạng (x, y, 1) trong đó 1 là viết tắt của 1 kênh. Bạn chỉ cần gọi plot_layerDefputs (...) để vẽ.

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

Điều gì xảy ra nếu mô hình có một vài đầu vào? Làm thế nào để bạn xác định đầu vào?
Antonio Sesto

Trong dòng này: layerDefputs_list = [op ([test_image, 1.]). Có 1. cần phải là 0? Có vẻ như 1 là viết tắt của đào tạo và 0 là viết tắt của thử nghiệm? Có phải vậy không?
Kongsea

Điều này không làm việc cho tôi. Tôi đã sử dụng một hình ảnh màu và nó gây ra lỗi cho tôi: UnlimitedArgumentError: input_2: 0 là cả được cung cấp và tìm nạp.
Vaibhav K

5

Từ: 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

Liên kết bị phản đối.
Saeed


5

Muốn thêm nhận xét này dưới dạng nhận xét (nhưng không có đại diện đủ cao.) Cho câu trả lời của @ indraforyou để khắc phục sự cố được đề cập trong nhận xét của @ mathtick. Để tránh InvalidArgumentError: input_X:Y is both fed and fetched.ngoại lệ, chỉ cần thay thế dòng outputs = [layer.output for layer in model.layers]bằng outputs = [layer.output for layer in model.layers][1:], tức là

thích ứng với ví dụ làm việc tối thiểu của 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 cố gắng của tôi cố gắng những thứ như outputs = [layer.output for layer in model.layers[1:]]không làm việc.


1
điều đó không chính xác Điều này chỉ khi lớp đầu vào được xác định đầu tiên.
Mpizos Dimitris

Cảm ơn, điều này hiệu quả với tôi và tôi chỉ muốn kiểm tra xem tôi hiểu tại sao, dựa trên nhận xét của Mpizos: mô hình của tôi chỉ có 3 lớp (nhúng từ - BiLSTM - CRF), vì vậy tôi đoán tôi phải loại trừ lớp [0] chỉ nhúng và không nên kích hoạt, phải không?
KMunro

@MpizosDimitris đúng vậy, nhưng trong ví dụ được cung cấp bởi @indraforyou (mà tôi đã sửa đổi), đây là trường hợp. @KMunro nếu tôi hiểu chính xác, thì lý do bạn không quan tâm đến đầu ra của lớp đầu tiên là vì nó đơn giản là đầu ra của từ nhúng mà chỉ là từ nhúng chính nó ở dạng tenor (chỉ là đầu vào phần "mạng" trong kerasmô hình của bạn ). Lớp nhúng từ của bạn tương đương với lớp đầu vào trong ví dụ được cung cấp ở đây.
KamKam

3

Giả sử bạn có:

1- Máy ảnh được đào tạo trước model.

2- Nhập xdưới dạng hình ảnh hoặc bộ hình ảnh. Độ phân giải của hình ảnh phải tương thích với kích thước của lớp đầu vào. Ví dụ: 80 * 80 * 3 cho hình ảnh 3 kênh (RGB).

3- Tên của đầu ra layerđể có được kích hoạt. Ví dụ: lớp "flatten_2". Điều này nên được bao gồm trong layer_namesbiến, đại diện cho tên của các lớp đã cho model.

4- batch_sizelà một đối số tùy chọn.

Sau đó, bạn có thể dễ dàng sử dụng get_activationchức năng để có được kích hoạt đầu ra layercho một đầu vào nhất định xvà được đào tạo trước 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

Trong trường hợp bạn có một trong những trường hợp sau:

  • lỗi: InvalidArgumentError: input_X:Y is both fed and fetched
  • trường hợp nhiều đầu vào

Bạn cần thực hiện các thay đổi sau:

  • thêm bộ lọc ra cho các lớp đầu vào trong outputsbiến
  • thay đổi nhỏ nhất trên functorsvòng lặp

Ví dụ tối thiểu:

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]

Có nghĩa là [x1, x2, xn, 1]gì? X1 của tôi không được xác định và tôi muốn hiểu những gì bạn đang xác định ở đó.
HashRocketSyntax

@HashRocketSyntax x1x2là đầu vào của mô hình. Như đã nêu rằng trong trường hợp bạn có 2 đầu vào trên mô hình của mình.
Mpizos Dimitris

1

Chà, những câu trả lời khác rất đầy đủ, nhưng có một cách rất cơ bản để "nhìn", chứ không phải "lấy" hình.

Chỉ cần làm một model.summary(). Nó sẽ in tất cả các lớp và hình dạng đầu ra của chúng. Giá trị "Không" sẽ cho biết kích thước thay đổi và kích thước đầu tiên sẽ là kích thước lô.


Đây là về đầu ra của lớp (đầu vào đã cho cho lớp cơ sở) chứ không phải lớp.
mathtick 15/03/19
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.