2017-10-04 250 views
1

说我们有一个卷积神经网络M.我可以用提取keras模型的最后一层为子模型

extractor = Model(M.inputs, M.get_layer('last_conv').output) 
features = extractor.predict(X) 

从图像中提取的特征我怎样才能将使用features预测类模型?

我不能使用以下几行,因为它需要输入模型作为占位符。

predictor = Model([M.get_layer('next_layer').input], M.outputs) 
pred = predictor.predict(features) 

我也不能使用K.function因为后来我想用它作为另一个模型的一部分,所以我会appliyng预测到tf.tensor,不np.array。

+0

什么是使用一个占位符的问题或一个输入层?这是正确的方法。 –

+1

@MatiasValdenegro如何在新的输入层之上堆叠**训练好的**预测器图层? – eclique

+0

使用功能性API,您只需使用您的模型,因为它是一个图层:in = Input(...)inter = yourModel(in)final = Dense(10)(inter) –

回答

2

这是不是最好的解决方案,但它的工作原理:

from keras.models import Sequential 
from keras.layers import Conv2D, MaxPooling2D 
from keras.layers import Dense, Dropout, Flatten 

def cnn(): 
    model = Sequential() 
    model.add(Conv2D(32, kernel_size=(3, 3), 
        activation='relu', 
        input_shape=(28, 28, 1), name='l_01')) 
    model.add(Conv2D(64, (3, 3), activation='relu', name='l_02')) 
    model.add(MaxPooling2D(pool_size=(2, 2), name='l_03')) 
    model.add(Dropout(0.25, name='l_04')) 
    model.add(Flatten(name='l_05')) 
    model.add(Dense(128, activation='relu', name='l_06')) 
    model.add(Dropout(0.5, name='l_07')) 
    model.add(Dense(10, activation='softmax', name='l_08')) 
    return model 

def predictor(input_shape): 
    model = Sequential() 
    model.add(Flatten(name='l_05', input_shape=(12, 12, 64))) 
    model.add(Dense(128, activation='relu', name='l_06')) 
    model.add(Dropout(0.5, name='l_07')) 
    model.add(Dense(10, activation='softmax', name='l_08')) 
    return model 

cnn_model = cnn() 
cnn_model.save('/tmp/cnn_model.h5') 

predictor_model = predictor(cnn_model.output.shape) 
predictor_model.load_weights('/tmp/cnn_model.h5', by_name=True) 
+0

是....到目前为止,这是我发现的唯一解决方案,重新创建模型的相关部分。 –

+0

是的,我也采取了重建预测器和加载重量。'by_name'是有用的,但我认为这应该是一个更清洁解决方案,如果我们不尽快提出更好的答案,我会接受答案。 – eclique

0

这取决于你想要做什么。

  • 如果你要扔掉的特征提取之后
  • 如果你打算训练特征提取后

如果你要使用提取的特征,但你不打算在训练用于生成它们的模型,你可以使用的预测方法得到的特征像你一样:

features = extractor.predict(X) 

然后保存其输出到文件(np.save或cPickle或其他)。 之后,您可以使用该新数据集作为新模型的输入。

如果你打算训练特征提取后,你将需要堆叠两个网络与VGG这里视为特征提取https://github.com/fchollet/keras/issues/4576

img_width, img_height = 150, 150 
vgg16_model = VGG16(include_top=False, weights='imagenet') 

input = Input(batch_shape=vgg16_model.output_shape) 
x = GlobalAveragePooling2D()(input) 
x = Dense(256, activation='relu')(x) 
x = Dropout(0.5)(x) 
predict = Dense(1, activation='sigmoid')(x) 
top_model = Model(input, predict) 

top_model.load_weights(os.path.join(data_path, 'VGG16Classifier.hdf5')) 

input = Input(shape=(3, img_width, img_height)) 
x = vgg16_model(input) 
predict = top_model(x) 
model = Model(input, predict) 

PS:此示例使用渠道第一顺序。如果你正在使用tensorflow你应该改变形状塑造=(img_width,IMG_HEIGHT,3)

+0

我想我可以在你提供的代码中看到解决方案。我将可以在稍后测试它。 但主要问题是在预测器,而不是提取器。你的意思是预测吗? 我会扔掉提取器,只会在预测器中使用固定的权重(未经过培训)。 – eclique

+0

如果您要扔掉提取器,这很简单,只需从模型中获取输出数据即可。当我说“预测”时,我的意思是使用extractor.predict来获得它的输出。在这个输出结束后,您基本上会使用新的数据集。使用keras/tensorflow构建符号模型,并以模型的拟合方法传递数据,就好像它是具有映射向量的任何其他数据集一样 - >标签 – maz

+1

我将extractor.predict(X)的要素与任何其他数据一起加载。问题是获得预测器**部分的**符号模型与训练后的权重。不幸的是,你的回答并不能解决这个问题。 :( – eclique