簡體   English   中英

提取keras模型的最后一層作為子模型

[英]Extracting last layers of keras model as a submodel

假設我們有一個卷積神經網絡 M。我可以通過使用從圖像中提取特征

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因為稍后我想將它用作另一個模型的一部分,所以我會將預測器應用於 tf.tensor,而不是 np.array。

這不是最好的解決方案,但它有效:

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)

模型中的每一層都有索引。 因此,如果您知道需要哪些層,就可以遍歷它們,將它們復制到新模型中。 此操作也應復制層內的權重。

這是一個模型(來自 Oli Blum 的回答):

  model = Sequential()
  # add some layers
  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'))

假設你想要最后三層:

def extract_layers(main_model, starting_layer_ix, ending_layer_ix):
  # create an empty model
  new_model = Sequential()
  for ix in range(starting_layer_ix, ending_layer_ix + 1):
    curr_layer = main_model.get_layer(index=ix)
    # copy this layer over to the new model
    new_model.add(curr_layer)
  return new_model

這取決於你想做什么。

  • 如果您之后打算扔掉特征提取器
  • 如果您打算稍后訓練特征提取器

如果您打算使用提取的特征,但不打算訓練用於生成它們的模型,則可以使用 predict 方法來獲取特征:

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,則應將形狀更改為 shape=(img_width, img_height,3 )

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM