首页 文章

在Keras中传递学习:ValueError:检查目标时出错:期望dense_26有形状(None,3)但是得到了有形状的数组(3000,1)

提问于
浏览
2

我有一个与转学习和VGG16 NN相关的非常简单的问题 .

这是我的代码:

import numpy as np
    from keras.preprocessing.image import ImageDataGenerator
    from keras.models import Sequential
    from keras.layers import Dropout, Flatten, Dense
    from keras import applications
    from keras import optimizers
    from keras.applications.vgg16 import VGG16
    from keras.applications.vgg16 import preprocess_input

    img_width, img_height = 150, 150
    top_model_weights_path = 'full_hrct_model_weights.h5'
    train_dir = 'hrct_data_small/train'
    validation_dir = 'hrct_data_small/validation'
    nb_train_samples = 3000
    nb_validation_samples = 600
    epochs = 50
    batch_size = 20


    def save_bottleneck_features():
        datagen = ImageDataGenerator(rescale=1. / 255)

        # build the vgg16 model
        model = applications.VGG16(include_top=False, weights='imagenet')

        generator = datagen.flow_from_directory(
            train_dir, 
            target_size=(img_width, img_height), 
            shuffle=False, 
            class_mode=None,
            batch_size=batch_size
        )  


        bottleneck_features_train = model.predict_generator(generator=generator, steps=nb_train_samples // batch_size)

        np.save(file="bottleneck_features_train_ternary_class.npy", arr=bottleneck_features_train)


        generator = datagen.flow_from_directory(
            validation_dir, 
            target_size=(img_width, img_height), 
            shuffle=False,
            class_mode=None,  
            batch_size=batch_size,    
        )

        bottleneck_features_validation = model.predict_generator(generator, nb_validation_samples // batch_size)

        np.save(file="bottleneck_features_validate_ternary_class.npy", arr=bottleneck_features_validation)

    save_bottleneck_features()
  • “找到属于3个 class 的3000张图片 . ”

  • “找到属于3个 class 的600张图片 . ”

def train_top_model():

     train_data = np.load(file="bottleneck_features_train_ternary_class.npy")
     train_labels = np.array([0] * (nb_train_samples // 2) + [1] * (nb_train_samples // 2))

     validation_data = np.load(file="bottleneck_features_validate_ternary_class.npy")
     validation_labels = np.array([0] * (nb_validation_samples // 2) + [1] * (nb_validation_samples // 2))

     model = Sequential()
     model.add(Flatten(input_shape=train_data.shape[1:]))  # don't need to tell batch size in input shape
     model.add(Dense(256, activation='relu'))
      model.add(Dense(3, activation='sigmoid'))

     print(model.summary)

     model.compile(optimizer='Adam', loss='binary_crossentropy', metrics=['accuracy'])

     model.fit(train_data, train_labels,
               epochs=epochs,
               batch_size=batch_size,
               validation_data=(validation_data, validation_labels))

     model.save_weights(top_model_weights_path)

train_top_model()

我得到的错误是这样的:


ValueError                                Traceback (most recent call last)
  <ipython-input-52-33db5c28e162> in <module>()
        2                epochs=epochs,
        3                batch_size=batch_size,
  ----> 4                validation_data=(validation_data, validation_labels))    

  /Users/simonalice/anaconda/lib/python3.5/site-packages/keras/models.py in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, **kwargs)
      854                               class_weight=class_weight,
      855                               sample_weight=sample_weight,
  --> 856                               initial_epoch=initial_epoch)
      857 
      858     def evaluate(self, x, y, batch_size=32, verbose=1,

  /Users/simonalice/anaconda/lib/python3.5/site-packages/keras/engine/training.py in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, **kwargs)
     1427             class_weight=class_weight,
     1428             check_batch_axis=False,
  -> 1429             batch_size=batch_size)
     1430         # Prepare validation data.
     1431         if validation_data:

  /Users/simonalice/anaconda/lib/python3.5/site-packages/keras/engine/training.py in _standardize_user_data(self, x, y, sample_weight, class_weight, check_batch_axis, batch_size)
     1307                                     output_shapes,
     1308                                     check_batch_axis=False,
  -> 1309                                     exception_prefix='target')
     1310         sample_weights = _standardize_sample_weights(sample_weight,
     1311                                                      self._feed_output_names)

  /Users/simonalice/anaconda/lib/python3.5/site-packages/keras/engine/training.py in _standardize_input_data(data, names, shapes, check_batch_axis, exception_prefix)
      137                             ' to have shape ' + str(shapes[i]) +
      138                             ' but got array with shape ' +
  --> 139                             str(array.shape))
      140     return arrays
      141 

  ValueError: Error when checking target: expected dense_32 to have shape (None, 3) but got array with shape (3000, 1)

以下是模型摘要:

Layer (type)                 Output Shape              Param #   
   =================================================================
    flatten_16 (Flatten)         (None, 8192)              0         
   _________________________________________________________________
    dense_31 (Dense)             (None, 256)               2097408   
   _________________________________________________________________
    dropout_16 (Dropout)         (None, 256)               0         
   _________________________________________________________________
    dense_32 (Dense)             (None, 3)                 771       
   =================================================================
     Total params: 2,098,179
     Trainable params: 2,098,179
     Non-trainable params: 0

我的困难凸显了我怀疑的一个根本性的误解,但我需要一些非常直接的解释 . 我在这次培训中有3节课 . 'hrct_data_small / train'包含3个文件夹,'hrct_data_small / validation'包含3个文件夹 .

第一:我认为顶级模型的最后一层是正确的:

model.add(Dense(3, activation='sigmoid'))

应该是“3”因为我有3个 class .

第二:

我 grab 了数据形状进行调查

train_data = np.load(file="bottleneck_features_train_ternary_class.npy")
  train_labels = np.array([0] * (nb_train_samples // 2) + [1] * (nb_train_samples // 2))
  validation_data =np.load(file="bottleneck_features_validate_ternary_class.npy")
  validation_labels = np.array([0] * (nb_validation_samples // 2) + [1] * (nb_validation_samples // 2))

然后

print("Train data shape", train_data.shape)
  print("Train_labels shape", train_labels.shape)
  print("Validation_data shape", validation_labels.shape)
  print("Validation_labels", validation_labels.shape)

结果是

Train data shape (3000, 4, 4, 512)
  Train_labels shape (3000,)
  Validation_data shape (600,)
  Validation_labels (600,)

那么,“训练数据形状”变量是否应该是形状(3000,3) .

我对这些基本问题表示道歉 - 如果我能够对此有一个清晰的思考,我将不胜感激 .

编辑:感谢下面Naseem的建议,我解决了他的所有观点,除了:

train_data按顺序返回训练数据,因此第一类(1000)然后第二类(1000)和第三类(1000) . 因此train_labels必须按顺序排列:

train_data = np.load(file="bottleneck_features_train_ternary_class.npy")
  train_labels = np.array([0] * 1000 + [1] * 1000 + [2] * 1000)
  validation_data = np.load(file="bottleneck_features_validate_ternary_class.npy")
  validation_labels = np.array([0] * 400 + [1] * 400 + [2] * 400)

然后我修复了这样的标签:

train_labels = np_utils.to_categorical(train_labels, 3)
  validation_labels = np_utils.to_categorical(validation_labels, 3)

这使得标签成为正确的形状并且一次性编码它们 . 我检查了前几个,他们是正确的 . 然后该模型起作用 .

作为补充评论 - 所有答案都在Keras文档中 . 如果我花了更多的时间阅读并减少了剪切和粘贴代码的时间,我就会把它弄好 . 学过的知识 .

1 回答

  • 4

    我不确定这会清除你的一切,但是我在你的代码中看到了一些错误:

    • 你创建标签的方式对我来说真的很奇怪 . 为什么将一半的数据设为0,另一半设为1:
    train_labels = np.array([0] * (nb_train_samples // 2) + [1] * (nb_train_samples // 2))
    

    这似乎不对 . 您需要更多地解释您想要预测的内容 . 通常你的标签应该用生成器生成并设置 class_mode='categorical' 而不是 class_mode=None 这将使生成器输出输入和目标,目标将是一个长度为3的热编码向量的系列 .

    • 您正在使用的损失是 loss='binary_crossentropy' . 当您对可以分为多个类别的图像进行分类时,或者当您只有2种类的可能性时,可以使用此方法 . 这不是你的情况(如果我理解正确的话) . 你应该使用: loss='categorical_crossentropy' . 这是当每个图像具有一个且不超过一个类作为目标时 .

    • 这与前一点相关联,即最后一层的激活: model.add(Dense(3, activation='sigmoid')) . sigmoid将允许您的输出为[1 1 0]或[1 1 1]或[0 0 0],这些是无效的,因为在您的情况下您只想预测一个类,您不希望您的图像被归类为属于3类 . 我们在这个分类案例中使用的是softmax . softmax将对输出进行归一化,使它们总和为1.您现在可以将输出解释为概率:[0.1 0.2 0.7],图像有10%的概率属于第一类,20%属于第二类,70 %到第三个 . 所以我会改为: model.add(Dense(3, activation='softmax'))

    总而言之,网络抱怨因为对于每个图像,它期望您提供的目标是长度为3的单热矢量,编码图像所属的类 . 你目前正在喂它只是一个数字0或1 .

    它更有意义吗?

相关问题