Реализуйте потерю восприятия с помощью предварительно обученного VGG с помощью keras

Я относительно новичок в DL и Keras.

Я пытаюсь реализовать потерю восприятия с помощью предварительно обученного VGG16 в Keras, но у меня есть некоторые проблемы. Я уже нашел этот вопрос, но все еще борюсь: /

Краткое объяснение того, что должна делать моя сеть:

У меня есть CNN (впоследствии называемый mainModel), который получает изображения в оттенках серого в качестве входных данных (#TrainData, 512, 512, 1) и выводит изображения в оттенках серого с тем же размером. Сеть должна уменьшить количество артефактов на изображениях - но я думаю, что для этого вопроса это не так важно. Вместо использования, например, MSE как функция потерь, я хотел бы реализовать потерю восприятия.

Что я хочу сделать (надеюсь, я правильно понял концепцию потери восприятия):

Я хотел бы добавить lossModel (предварительно обученный VGG16 с фиксированными параметрами) к моей mainModel. Затем я хотел бы передать вывод mainModel в lossModel. Кроме того, я передаю изображения меток (Y_train) в lossModel. Далее я сравниваю активации на определенном уровне (например, block1_conv2) модели потери, используя, например, MSE и используйте его как функцию потерь.

Что я сделал на данный момент:

Загрузите данные и создайте mainModel:

### Load data ###
with h5py.File('.\train_test_val.h5', 'r') as hf:
    X_train = hf['X_train'][:]
    Y_train = hf['Y_train'][:]
    X_test = hf['X_test'][:]
    Y_test = hf['Y_test'][:]
    X_val = hf['X_val'][:]
    Y_val = hf['Y_val'][:]

### Create Main Model ###
input_1 = Input((512,512,9))
conv0 = Conv2D(64, (3,3), strides=(1,1), activation=relu, use_bias=True, padding='same')(input_1)
.
.
.

mainModel = Model(inputs=input_1, outputs=output)

Создайте lossModel, добавьте его в mainModel и исправьте параметры:

### Create Loss Model (VGG16) ###
lossModel = vgg16.VGG16(include_top=False, weights='imagenet', input_tensor=mainModel.output, input_shape=(512,512, 1))
lossModel.trainable=False

for layer in lossModel.layers:
    layer.trainable=False

Создайте новую модель, включая обе сети, и скомпилируйте ее.

### Create new Model ###
fullModel = Model(inputs=mainModel.input, outputs=lossModel.output)

fullModel.compile(loss='mse', optimizer='adam',metrics=['mse','mae'])
fullModel.summary()

Отрегулируйте изображения этикеток, передав их через lossNetwork:

Y_train_lossModel = lossModel.predict(Y_train)

Установите полную модель, используя потерю восприятия:

fullModel.fit(X_train, Y_train_lossModel, batch_size=32, epochs=5, validation_data=[X_val,Y_val])

Возникающие проблемы:

  • VGG16 хочет получить входные данные формы (?,?, 3), но моя mainModel выводит изображение в оттенках серого (?,?, 1)

  • Некоторая проблема с добавлением lossModel к mainModel

RuntimeError: График отключен: невозможно получить значение для тензорного тензора ("conv2d_2 / Relu: 0", shape = (?, 512, 512, 3), dtype = float32) на уровне "input_2". Доступ к следующим предыдущим слоям был осуществлен без проблем: []

  • Как я могу рассчитать MSE при активации определенных слоев, а не на выходе lossModel?

Большое спасибо за вашу помощь и извините за очень длинный вопрос :)


person Midas.Inc    schedule 06.12.2017    source источник


Ответы (1)


Количество каналов

Что ж, первая проблема существенна.

Модели VGG были созданы для цветного изображения с 3 каналами ... так что это совершенно не подходящая модель для вашего случая. Не уверен, есть ли модели для черно-белых изображений, но вам стоит их поискать.

Обходной путь, который я не знаю, будет ли он работать хорошо, - это сделать 3 копии вывода mainModel.

tripleOut = Concatenate()([mainModel.output,mainModel.output,mainModel.output])

График отключен

Это означает, что нигде в вашем коде вы не создали связи между входом и выходом fullModel. Вы должны подключить выход mainModel к входу lossModel

Но сначала давайте подготовим модель VGG для нескольких выходов.

Подготовка lossModel для нескольких выходов

Вы должны выбрать, какие слои модели VGG будут использоваться для расчета потерь. Если вы используете только конечный результат, потери восприятия не будет, потому что конечный результат состоит в большей степени из концепций, чем из функций.

Итак, после выбора слоев составьте список их индексов или имен:

selectedLayers = [1,2,9,10,17,18] #for instance

Сделаем новую модель из VGG16, но с несколькими выходами:

#a list with the output tensors for each selected layer:
selectedOutputs = [lossModel.layers[i].output for i in selectedLayers]
     #or [lossModel.get_layer(name).output for name in selectedLayers]

#a new model that has multiple outputs:
lossModel = Model(lossModel.inputs,selectedOutputs)

Присоединение к моделям

Теперь мы создаем связь между двумя моделями.

Мы вызываем lossModel (как если бы это был слой), принимая выходные данные mainModel в качестве входных:

lossModelOutputs = lossModel(tripleOut) #or mainModel.output if not using tripeOut

Теперь, когда граф полностью подключен от входа mainModel к выходу lossModel, мы можем создать fullModel:

fullModel = Model(mainModel.input, lossModelOutputs)

#if the line above doesn't work due to a type problem, make a list with lossModelOutputs:
lossModelOutputs = [lossModelOutputs[i] for i in range(len(selectedLayers))]

Обучение

Возьмите предсказания этого нового lossModel, как и вы. Но в качестве обходного пути давайте также сделаем его тройным каналом:

triple_Y_train = np.concatenate((Y_train,Y_train,Y_train),axis=-1)
Y_train_lossModel = lossModel.predict(triple_Y_train)
#the output will be a list of numpy arrays, one for each of the selected layers   

Убедитесь, что вы сделали каждый слой lossModel необучаемым до fullModel.compile().

Если вы хотите использовать mse для всех выходов, просто выполните:

fullModel.compile(loss='mse', ...)

Если вы хотите разные потери для каждого слоя, передайте список потерь:

fullModel.compile(loss=[loss1,loss2,loss3,...], ...)

Дополнительные соображения

Поскольку VGG должен работать с изображениями в формате caffe, вы можете добавить несколько слоев после mainModel, чтобы сделать вывод подходящим. Это не обязательно, но будет использоваться лучшая производительность от VGG.

Посмотрите, как keras преобразует входное изображение в диапазоне от 0 до 255 в формат caffe здесь, в строке 15 или 44

person Daniel Möller    schedule 06.12.2017
comment
Большое спасибо за подробный и чрезвычайно полезный ответ - он отлично работает. Хотелось бы, чтобы за ваш ответ можно было проголосовать более одного раза :) Спасибо за миллион. - person Midas.Inc; 07.12.2017
comment
Вместо добавления VGG в качестве нового слоя, как я могу сделать это в пользовательской функции потерь? Я хочу использовать потерю VGG вместе с потерей MSE. Я хочу, чтобы на выходе модели было только изображение. Функция потерь должна принимать выходное изображение и целевое изображение, вычислять средневзвешенное значение потерь MSE и потерь VGG. Я получаю TypeError: An op outside of the function building code is being passed a "Graph" tensor. (я использую tenorflow 2.0) - person Nagabhushan S N; 18.12.2019