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

Error when using a pretrained MobileNet after loading datas (dimension error) with Python3.x Tensorflow2

我的数据集是一个训练数据文件夹和一个验证数据文件夹。 在每个文件夹(train 和 valid)中都有 .npy 文件。每个文件是(s,256,256,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 全局平均池化层、dropout,然后是密集层。这是我的代码:

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)

尝试更改行中的 batch_input_shape

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)

有关详细信息:请查看此 link

以下是一些可能对您有所帮助的提示。当您构建数据集时,对于图像数据,您应该通过绘制其中的一些样本来进行检查。例如:

 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 等大型数据集上训练过)的情况下,迁移学习的想法是可行的。但是,应该注意它是特定于您的任务的。使用预训练模型(使用 imagenet 权重)对医学图像(X 射线、断层扫描等)进行分类并不是一个好主意,因为它确实是特定的分类任务。但是,您可以开始添加一个带有 n_outputs 的分类层(取决于 类 的数量)并且只训练额外的层。

如果你想让模型更适合你的任务(你的数据集),你可以使用微调,这也是迁移学习,但你也在训练你的基础模型的一些层(看到你正在设置 base_model.trainable = False 并且只更新分类层的权重)。但是,在这种情况下,您还需要将 trainable = True 设置为 base_model 层的一部分(通常是最后一层),因为 CNN 模型的第一层通常学习图像的一般特征,而且可以肯定的是base_model 学习的权重适用于您的图像。

您还需要先训练您的分类层(就像您拥有的那样)。然后解冻 base_model 最后一层的一部分并重新训练。从 tensorflow here 查看本指南,您可以在其中找到相关示例。

试试这个:

我假设 X_train 的形式是:[[0.2,0.3,0.001,0.3,..],[0.02,0.4,...],[...]..] 而 y_train 的形式是:[[0],[1]..[]] 对吗?并且还根据preprocess_input函数归一化。

让我们放弃这两个 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)