我对DL和Keras相对较新。
我正试图在Keras中使用预训练的VGG16来实现感知损失但是有一些麻烦。我已经找到了question,但我仍在努力:/
我的网络应该做的简短说明:
我有一个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并修复params:
### 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()
通过传递丢失网络来调整标签图像:
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:图表已断开连接:无法在图层"获取张量张量(" conv2d_2 / Relu:0",shape =(?,512,512,3),dtype = float32)的值INPUT_2&#34 ;.访问以下先前的图层时没有问题:[]
非常感谢你的帮助,并为这个极长的问题感到抱歉:)
答案 0 :(得分:5)
嗯,第一个问题很重要。
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格式here at line 15 or 44