Хотя этот код, который я разместил, имеет проблему с низкой точностью (около 70%), но это другая история.

пример тонкой настройки VGG16 наблог keras, но я не могу воспроизвести это.

Точнее, вот код, используемый для инициализации VGG16 без верхнего слоя и для замораживания всех блоков, кроме самого верхнего:

WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5'
weights_path = get_file('vgg16_weights.h5', WEIGHTS_PATH_NO_TOP)

model = Sequential()
model.add(InputLayer(input_shape=(150, 150, 3)))
model.add(Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))

model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))

model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(256, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))

model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))

model.add(Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv1'))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2'))
model.add(Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv3'))
model.add(MaxPooling2D((2, 2), strides=(2, 2), name='block5_maxpool'))

model.load_weights(weights_path)

for layer in model.layers:
    layer.trainable = False

for layer in model.layers[-4:]:
    layer.trainable = True
    print("Layer '%s' is trainable" % layer.name)  

Далее создаем топ-модель с одним скрытым слоем:

top_model = Sequential()
top_model.add(Flatten(input_shape=model.output_shape[1:]))
top_model.add(Dense(256, activation='relu'))
top_model.add(Dropout(0.5))
top_model.add(Dense(1, activation='sigmoid'))
top_model.load_weights('top_model.h5')

Обратите внимание, что ранее он был обучен таким узким местам, как описано в сообщении в блоге. Затем добавьте эту топ-модель в базовую модель и скомпилируйте:

model.add(top_model)
model.compile(loss='binary_crossentropy',
              optimizer=SGD(lr=1e-4, momentum=0.9),
              metrics=['accuracy'])

И в конце концов, данные о кошках / собаках

batch_size = 16

train_datagen = ImageDataGenerator(rescale=1./255,
                                   shear_range=0.2,
                                   zoom_range=0.2,
                                   horizontal_flip=True)

test_datagen = ImageDataGenerator(rescale=1./255)

train_gen = train_datagen.flow_from_directory(
    TRAIN_DIR,
    target_size=(150, 150),
    batch_size=batch_size,
    class_mode='binary')

valid_gen = test_datagen.flow_from_directory(
    VALID_DIR,
    target_size=(150, 150),
    batch_size=batch_size,
    class_mode='binary')

model.fit_generator(
    train_gen,
    steps_per_epoch=nb_train_samples // batch_size,
    epochs=nb_epoch,
    validation_data=valid_gen,
    validation_steps=nb_valid_samples // batch_size)

Но вот ошибка, которую я получаю, когда пытаюсь соответствовать:

ValueError: Ошибка при проверке цели модели: ожидалось, что block5_maxpool будет иметь размеры 4>, но получит массив с формой (16, 1)

Поэтому, похоже, что-то не так с последним слоем пула в базовой модели. Или, возможно, я сделал что-то не так, пытаясь связать базовую модель с верхней.

У кого-нибудь есть подобная проблема? Или, может быть, есть лучший способ построения таких «сцепленных» моделей? я используюkeras==2.0.0 сtheano бэкенд.

Заметка: Я использовал примеры из GIST иapplications.VGG16 утилита, но есть проблемы, пытаясь объединить модели, я не слишком знаком сkeras функциональный API. Таким образом, это решение, которое я здесь предоставляю, является наиболее «успешным», то есть оно терпит неудачу только на подходящей стадии.

Обновление № 1

Хорошо, вот небольшое объяснение того, что я пытаюсь сделать. Прежде всего, я создаю узкие места из VGG16 следующим образом:

def save_bottleneck_features():
    datagen = ImageDataGenerator(rescale=1./255)
    model = applications.VGG16(include_top=False, weights='imagenet')

    generator = datagen.flow_from_directory(
        TRAIN_DIR,
        target_size=(150, 150),
        batch_size=batch_size,
        class_mode=None,
        shuffle=False)    
    print("Predicting train samples..")
    bottleneck_features_train = model.predict_generator(generator, nb_train_samples)
    np.save(open('bottleneck_features_train.npy', 'w'), bottleneck_features_train)

    generator = datagen.flow_from_directory(
        VALID_DIR,
        target_size=(150, 150),
        batch_size=batch_size,
        class_mode=None,
        shuffle=False)
    print("Predicting valid samples..")
    bottleneck_features_valid = model.predict_generator(generator, nb_valid_samples)
    np.save(open('bottleneck_features_valid.npy', 'w'), bottleneck_features_valid)

Затем я создаю топ-модель и обучаю ее следующим функциям:

def train_top_model():
    train_data = np.load(open('bottleneck_features_train.npy'))
    train_labels = np.array([0]*(nb_train_samples / 2) + 
                            [1]*(nb_train_samples / 2))
    valid_data = np.load(open('bottleneck_features_valid.npy'))
    valid_labels = np.array([0]*(nb_valid_samples / 2) +
                            [1]*(nb_valid_samples / 2))
    model = Sequential()
    model.add(Flatten(input_shape=train_data.shape[1:]))  
    model.add(Dense(256, activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(1, activation='sigmoid'))
    model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
    model.fit(train_data, train_labels,
              nb_epoch=nb_epoch,
              batch_size=batch_size,
              validation_data=(valid_data, valid_labels),
              verbose=1)
    model.save_weights('top_model.h5')   

В общем, есть две обученные модели,base_model с весами ImageNet иtop_model с весами, полученными из особенностей узкого места. И мне интересно, как их объединить? Это возможно или я что-то не так делаю? Потому что, как я вижу, ответ @ thomas-pinetz предполагает, что топ-модельне тренируется отдельно и сразу прилагается к модели, Не уверен, если мне ясно, вот цитата из блога:

Чтобы выполнить точную настройку, все слои должны начинаться с правильно обученных весов: например, вы не должны шлепать случайно инициализированную полностью подключенную сеть поверх предварительно обученной сверточной базы. Это происходит потому, что большие обновления градиента, запускаемые случайно инициализированными весами, разрушат изученные веса в сверточной основе. В нашем случае именно поэтому мы сначала обучаем классификатор верхнего уровня, а только затем начинаем тонкую настройку сверточных весов вместе с ним.

Ответы на вопрос(3)

Ваш ответ на вопрос