使用 keras 使用预训练的 VGG 实现感知损失
Posted
技术标签:
【中文标题】使用 keras 使用预训练的 VGG 实现感知损失【英文标题】:Implement perceptual loss with pretrained VGG using keras 【发布时间】:2018-05-20 09:09:47 【问题描述】:我对 DL 和 Keras 比较陌生。
我正在尝试使用 Keras 中预训练的 VGG16 来实现感知损失,但遇到了一些麻烦。我已经找到了question,但我还在苦苦挣扎:/
我的网络应该做什么的简短说明:
我有一个 CNN(后来称为 mainModel),它获取灰度图像作为输入(#TrainData, 512, 512, 1)并输出相同大小的灰度图像。网络应该减少图像中的伪影——但我认为这对这个问题并不重要。而不是使用例如MSE作为损失函数,我想实现感知损失。
我想做的事(希望我已经正确理解了知觉损失的概念):
我想在我的 mainModel 中附加一个 lossModel(预训练的 VGG16 和固定参数)。然后我想将mainModel的输出传递给lossModel。此外,我将标签图像 (Y_train) 传递给 lossModel。进一步,我使用例如比较 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:
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: cannot get value for tensor Tensor("conv2d_2/Relu:0", shape=(?, 512, 512, 3), dtype=float32) at layer "input_2".访问以下先前层没有问题:[]
如何计算特定层激活而不是 lossModel 输出的 MSE?非常感谢您的帮助,很抱歉这个非常长的问题:)
【问题讨论】:
【参考方案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)
加入模型
现在,我们在这里创建两个模型之间的连接。
我们将mainModel
的输出作为输入,调用lossModel
(就好像它是一个层):
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
确保在fullModel.compile()
之前使lossModel
的每一层都不可训练。
如果您希望所有输出都使用“mse”,您只需这样做:
fullModel.compile(loss='mse', ...)
如果您希望每一层都有不同的损失,请传递损失列表:
fullModel.compile(loss=[loss1,loss2,loss3,...], ...)
其他注意事项
由于 VGG 应该处理 caffe 格式的图像,您可能需要在 mainModel
之后添加几层以使输出适合。这不是绝对必需的,但它会使用 VGG 的最佳性能。
了解 keras 如何将输入图像从 0 到 255 转换为 caffe 格式here at line 15 or 44
【讨论】:
非常感谢您提供详细且非常有帮助的答案 - 效果很好。我希望有可能不止一次为您的答案投票 :) 谢谢一百万。 不添加 VGG 作为新层,如何在自定义损失函数中做到这一点?我想将 VGG 损失与 MSE 损失一起使用。我希望模型输出仅为图像。损失函数应该取输出图像和目标图像,计算 MSE 损失和 VGG 损失的加权平均值。我收到了TypeError: An op outside of the function building code is being passed a "Graph" tensor.
(我正在使用 tensorflow 2.0)以上是关于使用 keras 使用预训练的 VGG 实现感知损失的主要内容,如果未能解决你的问题,请参考以下文章