获取网络倒数第二个特征用于嵌入,但未能成功

我想得到一个图像嵌入,以便了解网络认为哪些图像更接近,哪些图像差异很大。最初,我打算使用Keras中的Tensorboard回调函数,但文档对我来说不够清晰,我找不到任何有用的例子来复制它。因此,为了确保我理解自己在做什么,我更愿意自己创建嵌入。

为此,我计划下载已经在我的数据上训练好的模型,移除最后几层(最后的dropout层和dense层),并在验证图像上进行预测以获取与每个图像相关联的特征。然后,我将简单地对这些特征进行主成分分析(PCA),并根据它们的头三个主成分值绘制图像。

但我觉得我误解了某些东西,因为当我移除最后几层时,模型的预测结果仍然是类别数量的大小,但对我来说,它应该是最有一层的大小,在我的例子中是128。

下面是用于澄清的代码(我只放了似乎有助于回答问题的行,但如果需要更多细节,请随时询问):

#model creationbase_model = applications.inception_v3.InceptionV3(include_top=False,                                                    weights='imagenet',                                                   pooling='avg',                                                    input_shape=(img_rows, img_cols, img_channel))#Adding custom Layersadd_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 modelmodel = 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_2model.layers[-1].pop()#remove dropout_1model.layers[-1].pop()model.summary() # last alyer output shape is : (None, 128), so the removal worked#predictmodel.predict(np.reshape(image,[1,image.shape[0],image.shape[1],3])) #output only two values

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


回答:

当使用Keras函数式API添加自定义层时的解决方案:

如果你使用Keras函数式API来添加你的自定义层,以下解决方案可以正常工作:

# base model creationbase_model = applications.inception_v3.InceptionV3(include_top=False,                                                    weights='imagenet',                                                   pooling='avg',                                                    input_shape=(150, 150, 3))# adding custom Layersx = 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 modelmodel = Model(inputs=base_model.input, outputs=out)model.compile(loss='categorical_crossentropy', optimizer='adam')

这是如何通过定义新模型来提取自定义层的激活值的方法:

# construct a new model to get the activations of custom layersnew_model = Model(model.inputs, [model.layers[-3].output,                                 model.layers[-2].output,                                 model.layers[-1].output])# predict one one random input sampleinp = np.random.rand(1, 150, 150, 3)output = new_model.predict([inp])# verify that's what we wantprint(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 Kfunc = 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 modesample_input = np.random.rand(1, 150, 150, 3)# train modeoutput = func([sample_input, 1])# test modeouput = func([sample_input, 0])

请注意,你需要使用K.learning_phase(),因为模型包含了在测试和训练模式下行为不同的层,如BatchNormalizationDropout


注意:上述解决方案在使用Sequential类添加自定义层时无法正常工作。这是因为在构建model时使用add_model(base_model.output),整个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()不起作用,因为你需要更新模型的一些内部属性(虽然,对于顺序模型,已经实现了一个内置的pop()方法)。

Related Posts

在使用k近邻算法时,有没有办法获取被使用的“邻居”?

我想找到一种方法来确定在我的knn算法中实际使用了哪些…

Theano在Google Colab上无法启用GPU支持

我在尝试使用Theano库训练一个模型。由于我的电脑内…

准确性评分似乎有误

这里是代码: from sklearn.metrics…

Keras Functional API: “错误检查输入时:期望input_1具有4个维度,但得到形状为(X, Y)的数组”

我在尝试使用Keras的fit_generator来训…

如何使用sklearn.datasets.make_classification在指定范围内生成合成数据?

我想为分类问题创建合成数据。我使用了sklearn.d…

如何处理预测时不在训练集中的标签

已关闭。 此问题与编程或软件开发无关。目前不接受回答。…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注