我是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])
出现的问题:
RuntimeError:图已断开连接:无法在层“input_2”上获得张量Tensor(“conv2d_2/Relu:0”,shape =(?, 512,512,3),dtype = float32)的值。可以顺利访问以下先前的图层:[]
非常感谢您的帮助,对于非常长的问题也很抱歉:)
最佳答案
通道数
好吧,第一个问题很重要。
VGG模型是为3个通道的彩色图像制作的,因此,这不是您所需要的正确模型。我不确定是否有适用于黑白图像的模型,但是您应该搜索它们。
我不知道是否可以很好地解决此问题的一种解决方法是制作mainModel
输出的3个副本。
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
进行预测。但对于解决方法,我们也将其设为三重 channel :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格式here at line 15 or 44