6

我对 DL 和 Keras 比较陌生。

我正在尝试使用 Keras 中预训练的 VGG16 来实现感知损失,但遇到了一些麻烦。我已经找到了这个问题,但我仍在苦苦挣扎:/

简要说明我的网络应该做什么:

我有一个 CNN(随后称为 mainModel),它获取灰度图像作为输入(#TrainData, 512, 512, 1)并输出相同大小的灰度图像。网络应该减少图像中的伪影——但我认为这对这个问题并不重要。我想实现感知损失,而不是使用例如 MSE 作为损失函数。

我想做什么(我希望我已经正确理解了感知损失的概念):

我想在我的 mainModel 中附加一个 lossModel(带有固定参数的预训练 VGG16)。然后我想将mainModel的输出传递给lossModel。此外,我将标签图像 (Y_train) 传递给 lossModel。进一步,我使用例如 MSE 比较 lossModel 的特定层(例如 block1_conv2)的激活并将其用作损失函数。

到目前为止我做了什么:

加载数据并创建 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:

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: Graph disconnected: 无法在“input_2”层获取张量 Tensor("conv2d_2/Relu:0", shape=(?, 512, 512, 3), dtype=float32) 的值。访问以下先前层没有问题:[]

  • 如何计算特定层激活而不是 lossModel 输出的 MSE?

非常感谢您的帮助,并对这个非常长的问题感到抱歉:)

4

1 回答 1

18

通道数

嗯,第一个问题很重要。

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 的最佳性能。

在第 15 或 44 行查看 keras 如何将范围从 0 到 255 的输入图像转换为 caffe 格式

于 2017-12-06T14:02:19.630 回答