我是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:图已断开连接:无法在层“input_2”上获得张量Tensor(“conv2d_2/Relu:0”,shape =(?, 512,512,3),dtype = float32)的值。可以顺利访问以下先前的图层:[]
  • 如何在激活特定层而不是lossModel的输出时计算MSE?

  • 非常感谢您的帮助,对于非常长的问题也很抱歉:)

    最佳答案

    通道数

    好吧,第一个问题很重要。

    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

    08-20 01:15