【问题标题】:Modify ResNet50 output layer for regression修改 ResNet50 输出层进行回归
【发布时间】:2019-02-05 15:21:50
【问题描述】:

我正在尝试为回归问题创建一个 ResNet50 模型,输出值范围为 -1 到 1。

我省略了 classes 参数,并在我的预处理步骤中将图像大小调整为 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,)

查看模型摘要,这是有道理的,因为最终 Dense 层的输出形状为 (None, 1000)

fc1000 (Dense)                  (None, 1000)         2049000     avg_pool[0][0]      

但我不知道如何修改模型。我通读了 Keras 文档并查看了几个示例,但我看到的几乎所有内容都是针对分类模型的。

如何修改模型以使其格式正确以进行回归?

【问题讨论】:

    标签: keras keras-layer resnet


    【解决方案1】:

    您的代码抛出错误,因为您使用的是原始全连接顶层,该层经过训练可将图像分类为 1000 个类别之一。为了使网络正常工作,你需要用你自己的替换这个顶层,它的形状应该与你的数据集和任务兼容。

    这是我用来创建 ImageNet 预训练模型的小 sn-p 模型,用于使用 Keras 进行回归任务(面部地标预测):

    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)
    

    就是这样。

    您还可以从 Keras 存储库中查看 this link,它显示了 ResNet50 的内部构造方式。我相信它会给你一些关于functional API和层替换的见解。


    另外,如果我们谈论的是微调预训练的 ImageNet 模型,我会说回归和分类任务并没有那么不同。任务的类型主要取决于你的损失函数和顶层的激活函数。否则,您仍然有一个带有N 输出的全连接层,但它们的解释方式不同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-15
      • 2020-12-20
      • 2020-10-13
      • 2019-10-25
      • 2021-09-07
      • 1970-01-01
      • 2021-05-21
      • 1970-01-01
      相关资源
      最近更新 更多