Изменить выходной слой ResNet50 для регрессии - PullRequest
0 голосов
/ 05 февраля 2019

Я пытаюсь создать модель 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)

Iполучим ошибку, которая говорит

ValueError: Error when checking target: expected fc1000 to have shape (1000,) but got array with shape (1,)

Глядя на сводку модели, это имеет смысл, так как конечный Плотный слой имеет выходную форму (Нет, 1000)

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

НоЯ не могу понять, как изменить модель.Я прочитал документацию Keras и просмотрел несколько примеров, но почти все, что я вижу, относится к модели классификации.

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

1 Ответ

0 голосов
/ 05 февраля 2019

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

...