使用Python3.x Tensorflow2加载数据(维度错误)后使用预训练MobileNet时出错

使用Python3.x Tensorflow2加载数据(维度错误)后使用预训练MobileNet时出错,python,keras,deep-learning,tensorflow2.0,transfer-learning,Python,Keras,Deep Learning,Tensorflow2.0,Transfer Learning,我的数据集是一个培训数据文件夹和一个验证数据文件夹。 在每个文件夹(train和valid)中都有.npy文件。每个文件是(s,256256,3)(卷中的s帧,3个通道,256个相同的高度和宽度)。还有一个CSV文件,每个文件都有一个标签 以下是我加载数据的代码: train_df = pd.read_csv(os.path.join(WORK_DIR, "train.csv"), names=['case', 'a

我的数据集是一个培训数据文件夹和一个验证数据文件夹。 在每个文件夹(train和valid)中都有.npy文件。每个文件是(s,256256,3)(卷中的s帧,3个通道,256个相同的高度和宽度)。还有一个CSV文件,每个文件都有一个标签

以下是我加载数据的代码:

train_df = pd.read_csv(os.path.join(WORK_DIR, 
                             "train.csv"), names=['case', 'abnormal'], 
                             dtype = {'case' : str, 'abnormal' : np.int64})
train_image = []
for i in tqdm(range(train_df.shape[0])):
    vol = np.load(os.path.join(WORK_DIR, train_folder, train_df[img_col][i]))
    train_image.append(vol)

X_train = np.array(train_image)
y_train= np.array(train_df.drop([img_col],axis=1)) 
train_loader = tf.data.Dataset.from_tensor_slices((X_train, y_train))
train_dataset = (train_loader.shuffle(X_train.shape[0]))
第一个问题:还好吗?

其思想是使用转移学习对数据进行分类(是正常还是异常?),我使用的是Tensorflow 2.4。所以我决定使用一个预训练的模型,提取特征,然后添加一个2D全局平均池层,退出,然后是密集层。这是我的密码:

preprocess_input = tf.keras.applications.mobilenet_v2.preprocess_input
base_model = tf.keras.applications.MobileNetV2(include_top=False, input_tensor=tf.keras.Input(batch_input_shape=(32,256,256, 3)),
                                               weights='imagenet')
base_model.trainable = False

global_average_layer = tf.keras.layers.GlobalAveragePooling2D()
max_pool_layer = tf.keras.layers.GlobalMaxPool2D()
prediction_layer = tf.keras.layers.Dense(1, activation='sigmoid')

inputs = tf.keras.Input((256,256,3), batch_size=32)
x = base_model(inputs, training=False)
x = global_average_layer(x)
x = tf.keras.layers.Dropout(0.2)(x)
outputs = prediction_layer(x)
model = tf.keras.Model(inputs, outputs)

base_learning_rate = 0.0001
model.compile(optimizer=tf.keras.optimizers.Adam(lr=base_learning_rate),
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])

history = model.fit(train_dataset,
                    epochs=initial_epochs,
                    validation_data=validation_dataset, batch_size=32)
我的错在哪里

这是我的问题:

ValueError: Input 0 is incompatible with layer model: expected shape=(None, 256, 256, 3), 
found shape=(None, 32, 256, 256, 3)

尝试在以下行中更改批处理输入形状:

base_model = tf.keras.applications.MobileNetV2(include_top=False, input_tensor=tf.keras.Input(batch_input_shape=(32,256,256, 3)),
                                                   weights='imagenet') 
通过这样做:

base_model._layers[0].batch_input_shape = (None, 256, 256, 3)

有关更多信息:请查看此

以下是一些可能对您有所帮助的提示。在构建数据集时,如果是图像数据,则应通过打印其中的一些示例进行检查。例如:

 train_loader = tf.data.Dataset.from_tensor_slices((X_train, y_train))
 for i, (x,y) in train_loader:
     if i == 1: break
     print(x.shape, y.shape)
     plt.imshow(x[i])
     plt.title(y[i])
在构建模型时,绘制模型以查看其构建是否正确实际上是一种很好的做法。如果可能的话,传递一些虚拟样本以确保一切正常

# define layer 
base_model = tf.keras.applications.MobileNetV2(include_top=False, 
                                               input_shape=(256,256,3),
                                               weights='imagenet')
base_model.trainable = False
global_average_layer = tf.keras.layers.GlobalAveragePooling2D()
prediction_layer = tf.keras.layers.Dense(1, activation='sigmoid')

# adding up 
inputs = tf.keras.Input((256,256,3), batch_size=32)
x = base_model(inputs, training=False)
x = global_average_layer(x)
x = tf.keras.layers.Dropout(0.2)(x)
outputs = prediction_layer(x)

# build all 
model = tf.keras.Model(inputs, outputs)
现在,您可以传递一些虚拟样本并绘制模型

model(tf.ones((1, 256, 256, 3))) # pass one dummy samples 
tf.keras.utils.plot_model(model) # to plot 

是的,转移学习的想法在您希望使用预先训练的模型(已经在大型数据集(如imagenet)上训练过)的情况下是可行的。但是,应该注意的是,它是特定于您的任务的。使用预先训练好的模型(使用图像净重)对医学图像(x射线、断层扫描等)进行分类不是一个好主意,因为这确实是一项特定的分类任务。但是,您可以开始添加一个具有n_输出的分类层(取决于类的数量),并仅训练该附加层

如果您想使模型更具体地针对您的任务(您的数据集),您可以使用精细调整,这也是转移学习,但您也在培训基础模型的某些层(请参见您正在设置基础模型。可培训=False,并且仅更新分类层的权重)。然而,在这种情况下,您还将为部分基本_模型层(通常是最后一层)设置trainable=True,因为CNN模型的第一层通常学习图像的一般特征,并且可以非常肯定的是,基本_模型学习的权重适用于您的图像

您还需要首先训练分类层(正如您所拥有的那样)。然后解冻基础模型最后一层的一部分并重新训练。从tensorflow查看本指南,您可以在那里找到这方面的示例

试试这个:

我假设X_列车的形式为:
[[0.2,0.3,0.001,0.3,…],[0.02,0.4,…],…]
,y_列车的形式为:
[[0],[1].[]
,对吗?并根据预处理输入函数进行归一化

让我们从拥有这两个numpy阵列开始,这是您的训练数据

base_model = tf.keras.applications.MobileNetV2(include_top=False, input_shape=(256,256,3),
                                               weights='imagenet')
base_model.trainable = False

global_average_layer = tf.keras.layers.GlobalAveragePooling2D()
max_pool_layer = tf.keras.layers.GlobalMaxPool2D() # I dont see where this is used
prediction_layer = tf.keras.layers.Dense(1, activation='sigmoid')

x = base_model.output
x = global_average_layer(x)
x = tf.keras.layers.Dropout(0.2)(x)
classification_layer = prediction_layer(x)
model = tf.keras.Model(inputs=base_model.input, outputs=classification_layer)

base_learning_rate = 0.0001
model.compile(optimizer=tf.keras.optimizers.Adam(lr=base_learning_rate),
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])

# I added ImageDataGenerator instead
train_generator = ImageDataGenerator(validation_split = 0.2).flow(X_train, 
                                                                  y_train, 
                                                                  batch_size = 32, 
                                                                  subset = 'training')
val_generator = ImageDataGenerator(validation_split=0.2).flow(X_train, 
                                                              y_train, 
                                                              batch_size = 32, 
                                                              subset = 'validation')

history = model.fit(train_generator, epochs = initial_epochs, validation_data= val_generator)

谢谢@zaw ish的回答。但我仍然有同样的错误:(嗨,Leili,我已经编辑了答案,并附加了一个链接。我希望它能有所帮助。嗨,zaw,谢谢你的更新,我检查了它并进行了更正,但仍然不起作用…我用VGG16更改了我的模型,但这是同一个问题。似乎输入的数据大小有问题。在我的dataloader数据形状中是(32256256,3)但他不把32作为批量大小,而是作为另一个维度。我不知道这是否清楚…你有什么想法吗?我迷失在我的脑海中,我不知道该怎么办…请上传到colab上,并与我共享链接,以便我可以正确调试它。谢谢@M.Innat我会尝试,它对检查所有内容都非常有用。我会告诉你它是否正确tGreat.让我知道它是否对你有效,或者可以问任何问题。你好@Francisco谢谢你的解释,我理解你所说的。然后,我检查了你在tensorflow中所说的链接,我添加了base_model.trainable=True并解冻一些层以重新培训第一层。但是,我仍然无法理解我的问题。这是same错误,似乎添加了无维度,但我不知道为什么..尝试设置input_shape=(256256,3)不要使用输入张量。@Leili_Kue你能检查一下这是否有效吗?嗨@Francisco我试着使用你提供的代码。在我检查之前,我有正确的X_火车表单,它似乎有效!非常感谢!@Leili_Kue听到这个消息太好了!没问题!如果你所有的问题都解决了,我的答案正确,请将它标记为已接受的answer:)