Решение при добавлении пользовательских слоев с использованием функционального API Keras:
Если вы используете Функциональный API Keras для добавления пользовательских слоев, следующие решения работают правильно:
# base model creation
base_model = applications.inception_v3.InceptionV3(include_top=False,
weights='imagenet',
pooling='avg',
input_shape=(150, 150, 3))
# adding custom Layers
x = Dense(128, activation='relu',input_shape=base_model.output_shape[1:],
kernel_regularizer=regularizers.l2(0.001))(base_model.output)
x = Dropout(0.60)(x)
out = Dense(2, activation='sigmoid')(x)
# creating the final model
model = Model(inputs=base_model.input, outputs=out)
model.compile(loss='categorical_crossentropy', optimizer='adam')
Вот как можно извлечь активации пользовательских слоев путем определения новой модели:
# construct a new model to get the activations of custom layers
new_model = Model(model.inputs, [model.layers[-3].output,
model.layers[-2].output,
model.layers[-1].output])
# predict one one random input sample
inp = np.random.rand(1, 150, 150, 3)
output = new_model.predict([inp])
# verify that's what we want
print(output[0].shape) # shape of first dense layer output, prints: (1, 128)
print(output[1].shape) # shape of dropout layer output, prints: (1, 128)
print(output[2].shape) # shape of second dense layer output, prints: (1, 2)
В качестве альтернативы, вы можете определить функцию Keras:
from keras import backend as K
func = K.function(inputs=model.inputs + [K.learning_phase()],
outputs=[model.layers[-3].output,
model.layers[-2].output,
model.layers[-1].output])
# usage of the defined function:
# the inputs should be a *list* of input arrays
# plus 1 or 0 for the train/test mode
sample_input = np.random.rand(1, 150, 150, 3)
# train mode
output = func([sample_input, 1])
# test mode
ouput = func([sample_input, 0])
Обратите внимание, что необходимо использовать K.learning_phase()
, поскольку модель содержит слои, такие как BatchNormalization
и Dropout
, которые ведут себя по-разному в тестовом и обучающем режимах.
ПРИМЕЧАНИЕ. Вышеуказанные решения НЕ работают должным образом, если вы используете класс Sequential
для добавления пользовательских слоев. Это потому, что при использовании add_model(base_model.output)
в построении model
все add_model
сохраняется как единое целое.слой model
.Вы можете проверить это, запустив model.summary()
или print(model.layers[-1])
.И нет никакого способа получить доступ к выходным данным средних слоев этой последовательной модели.Конечно, вы можете использовать model.layers[-1].layers[1].output
(который является выпадающим слоем):
new_model = Model(model.inputs, model.layers[-1].layers[1].output)
new_model.predict(...)
однако он будет жаловаться на то, что график отключен, так как исходный ввод последовательной модели не подается:
ValueError: Graph disconnected: cannot obtain value for tensor Tensor("dense_7_input:0", shape=(?, 2048), dtype=float32) at layer "dense_7_input". The following previous layers were accessed without issue: []
На самом деле, я ожидал, что внутренние слои последовательной модели (т.е. model.layers[-1].layer[1:]
) имеют дополнительные входящие и исходящие узлы, но, похоже, это не так.Я не знаю, пропускаю ли я что-то здесь, или это как-то ошибка или невозможность сделать в Керасе.
Примечание: На самом деле, с использованием pop()
на layers
атрибут объекта модели не работает, так как вам нужно обновить некоторые внутренние атрибуты модели (хотя, только для последовательных моделей встроенный pop()
метод был реализован).