修改 ResNet50 输出层以进行回归
Modify ResNet50 output layer for regression
我正在尝试为回归问题创建一个 ResNet50 模型,输出值范围为 -1 到 1。
我省略了 类 参数,并且在我的预处理步骤中我将图像大小调整为 224,224,3。
我尝试用
创建模型
def create_resnet(load_pretrained=False):
if load_pretrained:
weights = 'imagenet'
else:
weights = None
# Get base model
base_model = ResNet50(weights=weights)
optimizer = Adam(lr=1e-3)
base_model.compile(loss='mse', optimizer=optimizer)
return base_model
然后创建模型,打印摘要并使用fit_generator训练
history = model.fit_generator(batch_generator(X_train, y_train, 100, 1),
steps_per_epoch=300,
epochs=10,
validation_data=batch_generator(X_valid, y_valid, 100, 0),
validation_steps=200,
verbose=1,
shuffle = 1)
虽然上面写着
但我收到一个错误
ValueError: Error when checking target: expected fc1000 to have shape (1000,) but got array with shape (1,)
查看模型摘要,这是有道理的,因为最终的密集层的输出形状为 (None, 1000)
fc1000 (Dense) (None, 1000) 2049000 avg_pool[0][0]
但我不知道如何修改模型。我通读了 Keras 文档并查看了几个示例,但我看到的几乎所有内容都是针对分类模型的。
如何修改模型以使其格式正确以进行回归?
您的代码抛出错误,因为您使用的是 原始全连接顶层 ,该层经过训练可将图像分类为 1000 个 类 之一。为了使网络正常工作,您需要将顶层替换为您自己的顶层,其形状应与您的数据集和任务兼容。
这是我使用 Keras 为回归任务(人脸标志预测)创建 ImageNet 预训练模型的一个小片段:
NUM_OF_LANDMARKS = 136
def create_model(input_shape, top='flatten'):
if top not in ('flatten', 'avg', 'max'):
raise ValueError('unexpected top layer type: %s' % top)
# connects base model with new "head"
BottleneckLayer = {
'flatten': Flatten(),
'avg': GlobalAvgPooling2D(),
'max': GlobalMaxPooling2D()
}[top]
base = InceptionResNetV2(input_shape=input_shape,
include_top=False,
weights='imagenet')
x = BottleneckLayer(base.output)
x = Dense(NUM_OF_LANDMARKS, activation='linear')(x)
model = Model(inputs=base.inputs, outputs=x)
return model
在你的情况下,我猜你只需要将InceptionResNetV2
替换为ResNet50
。本质上,您正在创建一个没有顶层的预训练模型:
base = ResNet50(input_shape=input_shape, include_top=False)
然后在上面附加您的自定义层:
x = Flatten()(base.output)
x = Dense(NUM_OF_LANDMARKS, activation='sigmoid')(x)
model = Model(inputs=base.inputs, outputs=x)
就是这样。
您还可以检查 this link from the Keras repository that shows how ResNet50
is constructed internally. I believe it will give you some insights about the functional API 和图层替换。
此外,如果我们谈论微调预训练的 ImageNet 模型,我会说回归和分类任务没有太大区别。任务的类型主要取决于你的损失函数和顶层的激活函数。否则,您仍然有一个带有 N
个输出的全连接层,但它们的解释方式不同。
我正在尝试为回归问题创建一个 ResNet50 模型,输出值范围为 -1 到 1。
我省略了 类 参数,并且在我的预处理步骤中我将图像大小调整为 224,224,3。
我尝试用
创建模型def create_resnet(load_pretrained=False):
if load_pretrained:
weights = 'imagenet'
else:
weights = None
# Get base model
base_model = ResNet50(weights=weights)
optimizer = Adam(lr=1e-3)
base_model.compile(loss='mse', optimizer=optimizer)
return base_model
然后创建模型,打印摘要并使用fit_generator训练
history = model.fit_generator(batch_generator(X_train, y_train, 100, 1),
steps_per_epoch=300,
epochs=10,
validation_data=batch_generator(X_valid, y_valid, 100, 0),
validation_steps=200,
verbose=1,
shuffle = 1)
虽然上面写着
但我收到一个错误ValueError: Error when checking target: expected fc1000 to have shape (1000,) but got array with shape (1,)
查看模型摘要,这是有道理的,因为最终的密集层的输出形状为 (None, 1000)
fc1000 (Dense) (None, 1000) 2049000 avg_pool[0][0]
但我不知道如何修改模型。我通读了 Keras 文档并查看了几个示例,但我看到的几乎所有内容都是针对分类模型的。
如何修改模型以使其格式正确以进行回归?
您的代码抛出错误,因为您使用的是 原始全连接顶层 ,该层经过训练可将图像分类为 1000 个 类 之一。为了使网络正常工作,您需要将顶层替换为您自己的顶层,其形状应与您的数据集和任务兼容。
这是我使用 Keras 为回归任务(人脸标志预测)创建 ImageNet 预训练模型的一个小片段:
NUM_OF_LANDMARKS = 136
def create_model(input_shape, top='flatten'):
if top not in ('flatten', 'avg', 'max'):
raise ValueError('unexpected top layer type: %s' % top)
# connects base model with new "head"
BottleneckLayer = {
'flatten': Flatten(),
'avg': GlobalAvgPooling2D(),
'max': GlobalMaxPooling2D()
}[top]
base = InceptionResNetV2(input_shape=input_shape,
include_top=False,
weights='imagenet')
x = BottleneckLayer(base.output)
x = Dense(NUM_OF_LANDMARKS, activation='linear')(x)
model = Model(inputs=base.inputs, outputs=x)
return model
在你的情况下,我猜你只需要将InceptionResNetV2
替换为ResNet50
。本质上,您正在创建一个没有顶层的预训练模型:
base = ResNet50(input_shape=input_shape, include_top=False)
然后在上面附加您的自定义层:
x = Flatten()(base.output)
x = Dense(NUM_OF_LANDMARKS, activation='sigmoid')(x)
model = Model(inputs=base.inputs, outputs=x)
就是这样。
您还可以检查 this link from the Keras repository that shows how ResNet50
is constructed internally. I believe it will give you some insights about the functional API 和图层替换。
此外,如果我们谈论微调预训练的 ImageNet 模型,我会说回归和分类任务没有太大区别。任务的类型主要取决于你的损失函数和顶层的激活函数。否则,您仍然有一个带有 N
个输出的全连接层,但它们的解释方式不同。