训练具有不同输入形状的预训练序列模型
Training a pre-trained sequential model with different input shape
我有一个预训练的顺序 CNN 模型,我对 224x224x3 的图像进行了训练。以下是架构:
model = Sequential()
model.add(Conv2D(filters = 64, kernel_size = (5, 5), strides = 1, activation = 'relu', input_shape = (224, 224, 3)))
model.add(MaxPool2D(pool_size = (3, 3)))
model.add(Dropout(0.2))
model.add(Conv2D(filters = 128, kernel_size = (3, 3), strides = 1, activation = 'relu'))
model.add(MaxPool2D(pool_size = (2, 2)))
model.add(Dropout(0.2))
model.add(Conv2D(filters = 256, kernel_size = (2, 2), strides = 1, activation = 'relu'))
model.add(MaxPool2D(pool_size = (2, 2)))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128, activation = 'relu', use_bias=False))
model.add(Dense(num_classes, activation = 'softmax'))
model.summary()
作为参考,这里是模型摘要:model summary
我想在 40x40x3 大小的图像上重新训练这个模型。但是,我遇到以下错误:“ValueError:层 dense_12 的输入 0 与层不兼容:输入形状的预期轴 -1 的值为 200704 但收到的输入形状为(None, 256)”。
我应该怎么做才能解决此错误?
注意:我使用的是 Tensorflow 版本 2.4.1
问题是,在你的预训练模型中,你有一个 200704 的扁平形状作为输入形状(最后的第 4 行),然后输出大小为 128对于致密层(从最后一行开始的第 3 行)。现在你想对 40X40 的图像使用相同的预训练模型,这是行不通的。原因是:
1- 您的模型依赖于输入图像的形状。它不是一个端到端的转换模型,因为你在它们之间使用了密集层,这使得模型输入图像大小依赖。
2- 40x40 图像在所有 conv 层为 256 而不是 200704 之后的展平大小。
解决方案
1-要么你用自适应平均池化层改变展平部分,然后你最后一个带softmax的密集层就可以了。并再次在 224x224 图像上重新训练您的旧模型。然后你可以训练你的 40x40 图像。
2- 或者最简单的方法是只使用预训练模型的一个子集直到展平部分(排除展平部分)然后添加一个展平部分密集层和分类层(带 softmax 的层)。对于这种方法,您必须编写一个自定义模型,就像这里一样,只有第一部分是预训练模型的子集,展平和分类部分将是额外的。然后你可以在新数据集上训练整个模型。您还可以使用此方法利用迁移学习的好处,允许后向梯度仅流过新创建的线性层,而不流过预训练层。
我有一个预训练的顺序 CNN 模型,我对 224x224x3 的图像进行了训练。以下是架构:
model = Sequential()
model.add(Conv2D(filters = 64, kernel_size = (5, 5), strides = 1, activation = 'relu', input_shape = (224, 224, 3)))
model.add(MaxPool2D(pool_size = (3, 3)))
model.add(Dropout(0.2))
model.add(Conv2D(filters = 128, kernel_size = (3, 3), strides = 1, activation = 'relu'))
model.add(MaxPool2D(pool_size = (2, 2)))
model.add(Dropout(0.2))
model.add(Conv2D(filters = 256, kernel_size = (2, 2), strides = 1, activation = 'relu'))
model.add(MaxPool2D(pool_size = (2, 2)))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128, activation = 'relu', use_bias=False))
model.add(Dense(num_classes, activation = 'softmax'))
model.summary()
作为参考,这里是模型摘要:model summary
我想在 40x40x3 大小的图像上重新训练这个模型。但是,我遇到以下错误:“ValueError:层 dense_12 的输入 0 与层不兼容:输入形状的预期轴 -1 的值为 200704 但收到的输入形状为(None, 256)”。 我应该怎么做才能解决此错误?
注意:我使用的是 Tensorflow 版本 2.4.1
问题是,在你的预训练模型中,你有一个 200704 的扁平形状作为输入形状(最后的第 4 行),然后输出大小为 128对于致密层(从最后一行开始的第 3 行)。现在你想对 40X40 的图像使用相同的预训练模型,这是行不通的。原因是:
1- 您的模型依赖于输入图像的形状。它不是一个端到端的转换模型,因为你在它们之间使用了密集层,这使得模型输入图像大小依赖。
2- 40x40 图像在所有 conv 层为 256 而不是 200704 之后的展平大小。
解决方案
1-要么你用自适应平均池化层改变展平部分,然后你最后一个带softmax的密集层就可以了。并再次在 224x224 图像上重新训练您的旧模型。然后你可以训练你的 40x40 图像。
2- 或者最简单的方法是只使用预训练模型的一个子集直到展平部分(排除展平部分)然后添加一个展平部分密集层和分类层(带 softmax 的层)。对于这种方法,您必须编写一个自定义模型,就像这里一样,只有第一部分是预训练模型的子集,展平和分类部分将是额外的。然后你可以在新数据集上训练整个模型。您还可以使用此方法利用迁移学习的好处,允许后向梯度仅流过新创建的线性层,而不流过预训练层。