Ошибка при использовании вывода Vgg16 и добавлении дополнительных пользовательских слоев. ValueError: Ошибка при проверке ввода

Я пытаюсь получить выходные данные изображений (обучение и проверка), прошедших через сеть Vgg16 с помощью include_top = false , а затем добавить последние несколько слоев, как показано в приведенном ниже коде.

Я хочу, чтобы x хранил полную модель, чтобы я мог создать из нее файл tflite (включая vgg и добавленные мной слои)

from tensorflow.keras.models import Model
import os

x= vgg16.output
print(x.shape)
x = GlobalAveragePooling2D()(x)

x = Flatten()(x)
x = Dense(100)(x)
x = tf.keras.layers.LeakyReLU(alpha=0.2)(x)
x = (Dropout(0.5)) (x)
x = (Dense(50)) (x) 
x = tf.keras.layers.LeakyReLU(alpha=0.3)(x)
x = Dropout(0.3)(x)
x = Dense(num_classes, activation='softmax')(x)


# this is the model we will train
model = Model(inputs=vgg16.input, outputs=x)

# first: train only the top layers (which were randomly initialized)
# i.e. freeze all convolutional InceptionV3 layers
for layer in vgg16.layers:
    layer.trainable = False

model.compile(loss='categorical_crossentropy',
   optimizer=optimizers.RMSprop(lr=1e-4),
   metrics=['acc'])

# train the model on the new data for a few epochs
history = model.fit(train_data, train_labels, 
   epochs=15,
   batch_size=batch_size,
   validation_data=(validation_data, validation_labels))

model.save(top_model_weights_path)
(eval_loss, eval_accuracy) = model.evaluate( 
    validation_data, validation_labels, batch_size=batch_size, verbose=1)

Вывод x.shape (?, ?, ?, 512)

train_data.shape (1660, 2, 2, 512)

train_labels.shape (1660, 4)

validation_data.shape (137, 4)

validation_labels.shape (137, 2, 2, 512)

Ошибка:

ValueError: Ошибка при проверке ввода: ожидалось, что input_3 будет иметь форму (None, None, 3), но получил массив с формой (2, 2, 512)

Эта ошибка возникает в строке:

52 validation_data=(validation_data, validation_labels))


Предыдущий фрагмент кода, показанный ниже, отлично работает и дает точные результаты. train_data хранит пустой массив vgg16.predict_generator()


model = Sequential() 
model.add(Flatten(input_shape=train_data.shape[1:])) 
model.add(Dense(100)) 
model.add(tf.keras.layers.LeakyReLU(alpha=0.2))
model.add(Dropout(0.5)) 
model.add(Dense(50)) 
model.add(tf.keras.layers.LeakyReLU(alpha=0.3))
model.add(Dropout(0.3)) 
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy',
   optimizer=optimizers.RMSprop(lr=1e-4),
   metrics=['acc'])
history = model.fit(train_data, train_labels, 
   epochs=15,
   batch_size=batch_size,
   validation_data=(validation_data, validation_labels),
   callbacks =[tensorboard])
model.save(top_model_weights_path)
(eval_loss, eval_accuracy) = model.evaluate( 
    validation_data, validation_labels, batch_size=batch_size,     verbose=1)
print("[INFO] accuracy: {:.2f}%".format(eval_accuracy * 100)) 
print("[INFO] Loss: {}".format(eval_loss)) 

Этот шаг для передачи всех изображений (поезд, проверка, тест; здесь показан только поезд) через vgg16 выполняется для обоих приведенных выше фрагментов кода.

train_data_dir = 'data/train'
validation_data_dir = 'data/validation'
test_data_dir = 'data/test'

# number of epochs to train top model 
epochs = 7 #this has been changed after multiple model run 
# batch size used by flow_from_directory and predict_generator 
batch_size = 32

#Loading vgc16 model
vgg16 = applications.VGG16(include_top=False, weights='imagenet')
datagen = ImageDataGenerator(rescale=1. / 255) 
generator = datagen.flow_from_directory( 
    validation_data_dir, 
    target_size=(img_width, img_height), 
    batch_size=batch_size, 
    class_mode=None, 
    shuffle=False) 

nb_train_samples = len(generator.filenames) 
num_classes = len(generator.class_indices) 

predict_size_train = int(math.ceil(nb_train_samples / batch_size)) 

train_data = vgg16.predict_generator(generator, predict_size_train) 

person Dibyanshu Patnaik    schedule 02.06.2020    source источник
comment
Можете ли вы показать, как вы определяете модель VGG?   -  person Yoskutik    schedule 02.06.2020
comment
@Yoskutik в конце я добавил часть обработки изображений, которая показывает определение vgg. train_data хранит вывод изображений после того, как они были переданы через vgg.   -  person Dibyanshu Patnaik    schedule 02.06.2020


Ответы (1)


Что ж...

  1. Вы определили target_size=(img_width, img_height), и если (img_width, img_height) не является (224, 224), вам также необходимо определить target_size в модели VGG:
vgg16 = applications.VGG16(
  include_top=False, 
  weights='imagenet',
  target_size=(img_width, img_height, 3))
  1. Почему вы используете class_mode=None в datagen.flow_from_directory? None — это значение по умолчанию. Если вы хотите сделать его категоричным, напишите class_mode='categorical', но использование class_mode=None вообще не имеет смысла.

  2. predict_generator возвращает прогнозы. Сейчас predict_generator устарел, но вы можете использовать predict, который нормально работает с генераторами. Но predict следует использовать после тренировки. Правильный способ использования генераторов:

datagen = ImageDataGenerator(rescale=1. / 255) 
generator = datagen.flow_from_directory( 
  train_data_dir, 
  target_size=(img_width, img_height), 
  batch_size=batch_size, 
  shuffle=False)
// ...
history = model.fit(
  generator,
  epochs=15,
  steps_per_epoch=len(generator), 
  batch_size=batch_size,
  validation_data=validation_generator,
  validation_steps=len(validation_generator))

и позже, если вы хотите сделать прогноз, используйте: model.predict(test_generator)

  1. В этом случае вам не нужно использовать Flatten после GlobalAveragePooling2D. GlobalAveragePooling2D уменьшит вывод до одномерного массива.
person Yoskutik    schedule 02.06.2020
comment
Спасибо за решение. Всего одно небольшое изменение: вместо target_size в application.VGG16, поскольку это модель, следует использовать input_tensor=Input(shape=(img_height, img_width, 3))). - person Dibyanshu Patnaik; 03.06.2020