Python 采用VGG 16作为功能提取器的U-net类体系结构-连接层问题

Python 采用VGG 16作为功能提取器的U-net类体系结构-连接层问题,python,tensorflow,machine-learning,keras,keras-layer,Python,Tensorflow,Machine Learning,Keras,Keras Layer,我想构建一个U-net体系结构,使用VGG16模型作为我的编码器,在Imagenet数据集上预先训练权重。对于上采样,我想将编码器中某些层的输出与解码部分连接起来。几乎像这样(摘自TernausNet): 到目前为止,我的模型如下所示: from keras.applications.vgg16 import VGG16 as VGG16, preprocess_input encode_model = VGG16(input_shape=(768,768,3), include_top=Fa

我想构建一个U-net体系结构,使用VGG16模型作为我的编码器,在Imagenet数据集上预先训练权重。对于上采样,我想将编码器中某些层的输出与解码部分连接起来。几乎像这样(摘自TernausNet):

到目前为止,我的模型如下所示:

from keras.applications.vgg16 import VGG16 as VGG16, preprocess_input
encode_model = VGG16(input_shape=(768,768,3), include_top=False, weights='imagenet')
encode_model.trainable = False

from keras import models, layers

input_img = layers.Input((768,768,3), name = 'RGB_Input')

# output and start upsampling
features = encode_model(input_img)
conv_1 = layers.Conv2D(512, (3,3), activation='relu', padding='same')(features)
up_conv = layers.Conv2DTranspose(256, (3,3), strides=(2,2), activation='relu', padding='same')(conv_1)

# first concatenation block
concat_1 = layers.concatenate([encode_model.get_layer('block5_conv3').output, up_conv], axis=-1, name='concat_1')
conv_2 = layers.Conv2D(512, (3,3), activation='relu', padding='same')(concat_1)
up_conv_2 = layers.Conv2DTranspose(256, (3,3), strides=(2,2), activation='relu', padding='same')(conv_2)


# second concatenation block
concat_2 = layers.concatenate([up_conv_2, encode_model.get_layer('block4_conv3').output])
conv_3 = layers.Conv2D(512, (3,3), activation='relu', padding='same')(concat_2)
up_conv_3 = layers.Conv2DTranspose(128, (3,3), strides=(2,2), activation='relu', padding='same')(conv_3)

# third concatenation block
concat_3 = layers.concatenate([up_conv_3, encode_model.get_layer('block3_conv3').output])
conv_4 = layers.Conv2D(256, (3,3), activation='relu', padding='same')(concat_3)
up_conv_4 = layers.Conv2DTranspose(64, (3,3), strides=(2,2), activation='relu', padding='same')(conv_4)

# fourth concatenation block
concat_4 = layers.concatenate([up_conv_4, encode_model.get_layer('block2_conv2').output])
conv_5 = layers.Conv2D(128, (3,3), activation='relu', padding='same')(concat_4)
up_conv_5 = layers.Conv2DTranspose(32, (3,3), strides=(2,2), activation='relu', padding='same')(conv_5)

# fifth concatenation block
concat_4 = layers.concatenate([up_conv_5, encode_model.get_layer('block1_conv2').output])
conv_6 = layers.Conv2D(128, (3,3), activation='sigmoid', padding='same')(concat_4)

final_model = models.Model(inputs=[input_img], outputs=[conv_6])
final_model.summary()
之后,我编译并拟合模型:

import keras.backend as K
from keras.optimizers import Adam
from keras.losses import binary_crossentropy  

def dice_coef(y_true, y_pred, smooth=1):
    intersection = K.sum(y_true * y_pred, axis=[1,2,3])
    union = K.sum(y_true, axis=[1,2,3]) + K.sum(y_pred, axis=[1,2,3])
    return K.mean( (2. * intersection + smooth) / (union + smooth), 
    axis=0)

def dice_p_bce(in_gt, in_pred):
    return 1e-3*binary_crossentropy(in_gt, in_pred) - dice_coef(in_gt, 
    in_pred)

def true_positive_rate(y_true, y_pred):
    return K.sum(K.flatten(y_true)*K.flatten(K.round(y_pred)))/K.sum(y_true)   

final_model.compile(optimizer=Adam(1e-3, decay=1e-6), loss=dice_p_bce, 
    metrics=[dice_coef, 'binary_accuracy', true_positive_rate])

step_count = min(MAX_TRAIN_STEPS, balanced_train_df.shape[0]//BATCH_SIZE)
aug_gen = create_aug_gen(make_image_gen(balanced_train_df))
loss_history = [final_model.fit_generator(aug_gen, 
                         steps_per_epoch=step_count, 
                         epochs=NB_EPOCHS, 
                         validation_data=(valid_x, valid_y),
                         callbacks=callbacks_list,
                        workers=1)]`
然后我得到以下错误:

Graph disconnected: cannot obtain value for tensor Tensor("input_4:0", shape=(?, 768, 768, 3), dtype=float32) at layer "input_4". The following previous layers were accessed without issue: []
我读到当输入和输出不是同一个图形的一部分时会发生这种情况。我认为通过这一点,我连接了两个图表:

input_img = layers.Input((768,768,3), name = 'RGB_Input')

# output and start upsampling
features = encode_model(input_img)
conv_1 = layers.Conv2D(512, (3,3), activation='relu', padding='same')(features)

我犯了什么错

我更新了我的答案,以符合编辑的问题

我认为问题在于这方面:

features = encode_model(input_img)
encode_model
是一个keras模型,您尝试将自定义输入层传递给它。这当然不是必需的。请尝试以下操作:

# necessary imports
encode_model = VGG16(input_shape=(768,768,3), include_top=False, weights='imagenet')
conv_1 = layers.Conv2D(512, (3,3), activation='relu', padding='same')(encode_model.output)  # need to pass the output tensor to the conv_1 layer
# define the rest of your model as you have it

因为VGG16中已经有一个输入层,所以在这种情况下,您不需要定义新的输入层。只需使用现有的一个:

decode_features = decode_model.output

# ...

final_model = models.Model(inputs=[decode_model.input], outputs=[conv_6])
更新:如果要防止修改VGG16的权重,使用
trainable
参数明确地冻结其所有层:

for layer in decode_model.layers:
    layer.trainable = False

只需确保在编译最终模型之前执行此操作。

我尝试了此操作,然后得到了错误:“Tensor”对象没有属性“output”,我相信通过将输入提供给模型,我确实可以从VGG16模型中获得作为Tensor的输出。问题最有可能出现在连接中。当我在第一次连接之前使用输出创建模型时,它会编译并显示所有层。@user3578476我更改了答案以匹配新的变量名。首先转储自定义输入,然后将
encode_模型传递给
conv_1
以连接图形。这很有意义,也很有效。但是现在VGG16层又可以训练了。我想使用Imagenet中预先训练好的权重来处理这些问题,只需训练解码部分(级联和上采样层)。权重仍然会像这样初始化吗?我在第三行这样做。但不知何故,他“爆炸”了整个模型,使层再次可训练。在图层概述中,vgg16不显示在一行中,而是显示在模型内的所有图层。我得到以下输出:
总参数:28504608可训练参数:28504608不可训练参数:0
@user3578476请将
编译
拟合
调用添加到您的帖子中好吗?@user3578476再次查看我更新的答案。在这种情况下,您需要明确冻结图层。如果下面的任何答案解决了您的问题,请单击答案旁边的复选标记将其标记为“已回答”,以接受该问题-请参阅