Измените выходной слой ResNet50 для регрессии

Я пытаюсь создать модель 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 и просмотрел несколько примеров, но почти все, что я вижу, относится к модели классификации.

Как я могу изменить модель, чтобы она была правильно отформатирована для регрессии?


person DaveS    schedule 05.02.2019    source источник


Ответы (1)


Ваш код выдает ошибку, потому что вы используете исходный полностью подключенный верхний слой, который был обучен классифицировать изображения по одному из 1000 классов. Чтобы сеть работала, вам необходимо заменить этот верхний слой своим собственным, форма которого должна соответствовать вашему набору данных и задаче.

Вот небольшой фрагмент, который я использовал для создания предварительно обученной модели ImageNet для задачи регрессии (прогнозирование ориентиров на лицах) с помощью 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, показывающий, как ResNet50 устроен внутри. Я считаю, что это даст вам некоторое представление о функциональном API и замене слоев.


Кроме того, я бы сказал, что задачи регрессии и классификации не сильно отличаются, если мы говорим о тонкой настройке предварительно обученных моделей ImageNet. Тип задачи в основном зависит от вашей функции потерь и функции активации верхнего уровня. В противном случае у вас все еще есть полностью связанный слой с N выходами, но они интерпретируются по-другому.

person devforfu    schedule 05.02.2019