使用TimeDistributed预训练Keras卷积神经网络

7

我有一个问题,我想在TimeDistributed层中使用预训练的CNN网络,但我在实现过程中遇到了一些问题。

这是我的模型:

def bnn_model(max_len):
    # sequence length and resnet input size
    x = Input(shape=(maxlen, 224, 224, 3))

    base_model = ResNet50.ResNet50(weights='imagenet',  include_top=False)

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

    som = TimeDistributed(base_model)(x)

    #the ouput of the model is [1, 1, 2048], need to squeeze
    som = Lambda(lambda x: K.squeeze(K.squeeze(x,2),2))(som)

    bnn = Bidirectional(LSTM(300))(som)
    bnn = Dropout(0.5)(bnn)

    pred = Dense(1, activation='sigmoid')(bnn)

    model = Model(input=x, output=pred)

    model.compile(optimizer=Adam(lr=1.0e-5), loss="mse", metrics=["accuracy"])

    return model

编译模型时没有错误。但是当我开始训练时,出现以下错误:

tensorflow/core/framework/op_kernel.cc:975] Invalid argument: You must feed a value for placeholder tensor 'input_2' with dtype float
[[Node: input_2 = Placeholder[dtype=DT_FLOAT, shape=[], _device="/job:localhost/replica:0/task:0/gpu:0"]()]]

我检查了一下,发现我确实发送了float32类型的参数,但输入1是预训练Resnet中存在的输入2。

为了简单明了,这里是模型摘要。(注意:奇怪的是它没有显示Resnet内部发生的事情,但不要紧)

____________________________________________________________________________________________________
Layer (type)                     Output Shape          Param #     Connected to                     
====================================================================================================
input_1 (InputLayer)             (None, 179, 224, 224, 0                                            
____________________________________________________________________________________________________
timedistributed_1 (TimeDistribut (None, 179, 1, 1, 204 23587712    input_1[0][0]                    
____________________________________________________________________________________________________
lambda_1 (Lambda)                (None, 179, 2048)     0           timedistributed_1[0][0]          
____________________________________________________________________________________________________
bidirectional_1 (Bidirectional)  (None, 600)           5637600     lambda_1[0][0]                   
____________________________________________________________________________________________________
dropout_1 (Dropout)              (None, 600)           0           bidirectional_1[0][0]            
____________________________________________________________________________________________________
dense_1 (Dense)                  (None, 1)             601         dropout_1[0][0]                  
====================================================================================================
Total params: 29,225,913
Trainable params: 5,638,201
Non-trainable params: 23,587,712
____________________________________________________________________________________________________

我猜测我没有正确使用TimeDistributed,并且我发现没有人尝试这样做。我希望有人可以指导我。
编辑:
问题出在ResNet50.ResNet50(weights='imagenet', include_top=False) 在图中创建了自己的输入。
所以,我想我需要像这样做ResNet50.ResNet50(weights='imagenet', input_tensor=x, include_top=False),但是我不知道如何将其与TimeDistributed结合使用。
我已经尝试过了。
base_model = Lambda(lambda x : ResNet50.ResNet50(weights='imagenet',  input_tensor=x, include_top=False))
som = TimeDistributed(base_model)(in_ten)

但是它并没有生效。

似乎要求使用浮点值占位符。您可以追踪tf.Session.run调用中传递给'feed_dict'的内容吗? - drpng
tensorflow_backend.py 中,我打印了 feed_dict,得到了这个 [<tf.Tensor 'input_1:0' shape=(?, 179, 224, 224, 3) dtype=float32>, <tf.Tensor 'dense_1_target:0' shape=(?, ?) dtype=float32>, <tf.Tensor 'keras_learning_phase:0' shape=<unknown> dtype=bool>, <tf.Tensor 'dense_1_sample_weights:0' shape=(?,) dtype=float32>]。ResNet 仍然使用 placeholder 进行定义,但实际上不应该这样做。 - rAyyy
我相当确定我应该做类似于ResNet50.ResNet50(weights='imagenet', input_tensor=x, include_top=False)这样的事情,这样在base_model中就没有占位符了,但是我不知道如何在TimeDistributed中实现它。 - rAyyy
2个回答

4

我的简单解决方案相当不错。

考虑到您正在使用来自Keras的预训练网络,您也可以将其替换为您自己的预训练网络。

以下是一个简单的解决方案:

model_vgg=keras.applications.VGG16(input_shape=(256, 256, 3),
                                           include_top=False,
                                           weights='imagenet')
model_vgg.trainable = False
model_vgg.summary()

如果您想使用任何中间层,则可以将'block2_pool'替换为上一层的名称。
intermediate_model= Model(inputs=model_vgg.input, outputs=model_vgg.get_layer('block2_pool').output)
intermediate_model.summary()

最后将其包装在TimeDistributed层中

input_tensor = Input(shape=(time_steps,height, width, channels))
timeDistributed_layer = TimeDistributed( intermediate_model )(input_tensor)

现在,您可以简单地执行以下操作:
my_time_model = Model( inputs = input_tensor, outputs = timeDistributed_layer )

我们如何获得像UNET架构中跳跃连接的多层? - Kiran Shahi

1
我的快速解决方案有点丑陋。我只是复制了ResNet的代码,并将TimeDistributed添加到所有层中,然后从“基本”ResNet加载权重到我的自定义ResNet中。
注意:
要能够分析这样的图像序列确实需要大量的GPU内存。

实际上 - 没有其他办法 :< 您的解决方案目前是最好的可能性。 - Marcin Możejko
它将从头开始运行,不执行迁移学习。所以毫无用处。 - Pritul Dave

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接