获取网络的前一个嵌入功能,但不起作用

get the before last feature of network for embedding, is not working

我想要一个图像嵌入来了解网络正在看的哪些图像更接近,哪些图像对他来说似乎非常不同。 首先,我想在 Keras 中使用 Tensorboard 回调,但文档对我来说不够清晰,我找不到任何有用的示例来重现它。因此,为了确保理解我在做什么,我更愿意自己进行嵌入。

为此,我计划下载已经在我的数据上训练过的模型,删除最后一层(最后一个丢失层和密集层),并对验证图像进行预测以获得与每个图像相关的特征。然后我会简单地对这些特征进行 PCA 并根据它们的前三个主成分值绘制图像。

但我想我误解了一些东西,因为当我删除最后一层时,模型预测仍然是 类 的大小,但对我来说它应该是最后一层的大小,在我的例子中是 128。

下面是澄清代码(我只是放了一些似乎对回答问题有用的行,但请不要犹豫,询问更多细节):

#model creation
base_model = applications.inception_v3.InceptionV3(include_top=False, 
                                                   weights='imagenet',
                                                   pooling='avg', 
                                                   input_shape=(img_rows, img_cols, img_channel))
#Adding custom Layers
add_model = Sequential()
add_model.add(Dense(128, activation='relu',input_shape=base_model.output_shape[1:],
                    kernel_regularizer=regularizers.l2(0.001)))
add_model.add(Dropout(0.60))
add_model.add(Dense(2, activation='sigmoid'))   
# creating the final model
model = Model(inputs=base_model.input, outputs=add_model(base_model.output))

然后我在具有两个 类 的数据集上训练模型,并加载模型及其权重以生成特征:

model = load_model(os.path.join(ROOT_DIR,'model_1','model_cervigrams_all.h5'))
#remove the last two layers
#remove dense_2
model.layers[-1].pop()
#remove dropout_1
model.layers[-1].pop()
model.summary() # last alyer output shape is : (None, 128), so the removal worked
#predict
model.predict(np.reshape(image,[1,image.shape[0],image.shape[1],3])) #output only two values

我哪里错了?您有什么建议吗?

使用Keras函数添加自定义图层时的解决方法API:

如果您使用 Keras functional API 添加自定义图层,则以下解决方案可以正常工作:

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

请注意,you need to 使用 K.learning_phase(),因为模型包含 BatchNormalizationDropout 等层,它们在测试和训练模式下表现不同。


注意:如果您使用 Sequential class 添加自定义图层,上述解决方案将无法正常工作。 那是因为使用 add_model(base_model.output)model的构造中,整个add_model作为model的一层存储。您可以通过 运行 model.summary()print(model.layers[-1]) 来验证这一点。并且无法访问此顺序模型的中间层的输出。当然可以使用model.layers[-1].layers[1].output(也就是dropout层):

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:])具有额外的入站和出站节点,但似乎并非如此。我不知道我是否遗漏了一些东西,或者它是 Keras 中的一个错误或不可能做的事情。


旁注:实际上,在模型对象的 layers 属性上使用 pop() does not work since you need to update some of the internal attributes of the model (although, only for sequential models a built-in pop() 方法已经实现)。