Deep learning Keras中的转移学习:ValueError:检查目标时出错:预期密集_26具有形状(无,3),但获得具有形状(3000,1)的阵列

Deep learning Keras中的转移学习:ValueError:检查目标时出错:预期密集_26具有形状(无,3),但获得具有形状(3000,1)的阵列,deep-learning,keras,Deep Learning,Keras,我有一个关于迁移学习和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

我有一个关于迁移学习和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()
  • “找到3000张属于3个类别的图像。”

  • “找到了600张属于3类的图像。”

我得到的错误是:


我在这里遇到的困难突出了我的一个基本误解,我怀疑,但我需要一些非常直截了当的解释。这次培训我有三节课。”hrct_数据_小型/列车”包含3个文件夹,“hrct_数据_小型/验证”包含3个文件夹

第一:我认为顶层模型的最后一层:

   model.add(Dense(3, activation='sigmoid'))
应该是“3”,因为我有3节课

第二:

我抓起数据形状进行调查

  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))
然后

结果是

  Train data shape (3000, 4, 4, 512)
  Train_labels shape (3000,)
  Validation_data shape (600,)
  Validation_labels (600,)
因此,“Train data shape”变量是否应为形状(3000,3)

对于这些基本问题,我深表歉意——如果我能简单地对此有一些清晰的想法,我将不胜感激

编辑:多亏了下面纳西姆的建议,我解决了他所有的问题,除了:

train_数据按顺序返回训练数据,因此第一类(1000)返回,第二类(1000)返回,第三类(1000)返回。因此,列车标签的顺序应为:

  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文档中。如果我花多一点时间阅读,少一点时间剪切和粘贴代码,我就会做对了。吸取的教训

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

  • 你创建标签的方式对我来说真的很奇怪。为什么将一半的数据作为0,另一半作为1放入:

    train_labels = np.array([0] * (nb_train_samples // 2) + [1] * (nb_train_samples // 2)) 
    
    这似乎不对。你需要多解释一下你想要预测的是什么。通常,标签应与生成器一起生成,并设置为
    class_mode='classifical'
    而不是
    class_mode=None
    ,这将使生成器同时输出输入和目标,目标将是一系列长度为3的热编码向量

  • 您使用的损失是
    loss='binary\u crossentropy'
    。当您对可以分为多个类别的图像进行分类时,或者当您只有两种分类可能性时,可以使用此选项。这不是你的情况(如果我理解正确的话)。您应该使用:
    loss='classifical\u crossentropy'
    。这是指每个图像都有一个且不超过一个类作为目标

  • 这链接到上一点,即最后一层的激活:
    model.add(稠密(3,activation='sigmoid'))
    。sigmoid将允许您的输出为[1 1 0]或[1 1 1]或[0 0 0 0],这些是无效的,因为在您的情况下,您只想预测一个类别,而不希望您的图像被分类为属于这3个类别。我们在本分类案例中使用的是softmax。softmax将标准化输出,使其总和为1。现在可以将输出解释为概率:[0.1 0.2 0.7],图像属于第一类的概率为10%,属于第二类的概率为20%,属于第三类的概率为70%。因此,我将改为:
    model.add(稠密(3,activation='softmax'))

  • 总而言之,网络会抱怨,因为对于每个图像,它期望您提供的目标是长度为3的一个热向量,对图像所属的类进行编码。你现在喂它的只是一个数字0或1


    这更有意义吗?

    Nassim。这对我来说是极好的教学。我理解你所说的,并且看到了这些错误(基本错误)。我将尝试实施您建议的修改,并提供反馈。非常感谢先生:)如果它不起作用,请澄清你的问题出了什么问题。如果可行,别忘了为下一代验证答案。
      Train data shape (3000, 4, 4, 512)
      Train_labels shape (3000,)
      Validation_data shape (600,)
      Validation_labels (600,)
    
      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)
    
    train_labels = np.array([0] * (nb_train_samples // 2) + [1] * (nb_train_samples // 2))