首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Keras TimeDistributed不掩蔽CNN模型

Keras TimeDistributed不掩蔽CNN模型
EN

Stack Overflow用户
提问于 2018-04-30 05:49:09
回答 3查看 2.9K关注 0票数 9

为了举例说明,我有一个输入,包含2个图像,总形状(2,299,299,3)。我试图在每个映像上应用inceptionv3,然后使用LSTM处理输出。我使用掩蔽层来排除正在处理的空白图像(如下所示)。

守则是:

代码语言:javascript
复制
import numpy as np
from keras import backend as K
from keras.models import Sequential,Model
from keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D, BatchNormalization, \
Input, GlobalAveragePooling2D, Masking,TimeDistributed, LSTM,Dense,Flatten,Reshape,Lambda, Concatenate
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.applications import inception_v3

IMG_SIZE=(299,299,3)
def create_base():
    base_model = inception_v3.InceptionV3(weights='imagenet', include_top=False)
    x = GlobalAveragePooling2D()(base_model.output)
    base_model=Model(base_model.input,x)
    return base_model


base_model=create_base()

#Image mask to ignore images with pixel values of -1
IMAGE_MASK = -2*np.expand_dims(np.ones(IMG_SIZE),0)

final_input=Input((2,IMG_SIZE[0],IMG_SIZE[1],IMG_SIZE[2]))

final_model = Masking(mask_value = -2.)(final_input)
final_model = TimeDistributed(base_model)(final_model)
final_model = Lambda(lambda x: x, output_shape=lambda s:s)(final_model)
#final_model = Reshape(target_shape=(2, 2048))(final_model)
#final_model = Masking(mask_value = 0.)(final_model)
final_model = LSTM(5,return_sequences=False)(final_model)
final_model = Model(final_input,final_model)


#Create a sample test image
TEST_IMAGE = np.ones(IMG_SIZE)

#Create a test sample input, consisting of a normal image and a masked image
TEST_SAMPLE = np.concatenate((np.expand_dims(TEST_IMAGE,axis=0),IMAGE_MASK))



inp = final_model.input                                           # input placeholder
outputs = [layer.output for layer in final_model.layers]          # all layer outputs
functors = [K.function([inp]+ [K.learning_phase()], [out]) for out in outputs]
layer_outs = [func([np.expand_dims(TEST_SAMPLE,0), 1.]) for func in functors]

这是不正确的。具体来说,模型应该掩盖输入的IMAGE_MASK部分,但是它用开始(提供非零输出)来处理它。详情如下:

1,LSTM输出很好:

[array([[-0.15324114, -0.09620268, -0.01668587, 0.07938149, -0.00757846]], dtype=float32)]

层_out-2和层_out-3,LSTM输入错误,它应该在第二个数组中有所有的零:

[array([[[ 0.37713543, 0.36381325, 0.36197218, ..., 0.23298527, 0.43247852, 0.34844452], [ 0.24972123, 0.2378867 , 0.11810347, ..., 0.51930511, 0.33289322, 0.33403745]]], dtype=float32)]

图层-4,CNN的输入被正确地屏蔽:

代码语言:javascript
复制
[[ 1.,  1.,  1.],
           [ 1.,  1.,  1.],
           [ 1.,  1.,  1.],
           ..., 
           [ 1.,  1.,  1.],
           [ 1.,  1.,  1.],
           [ 1.,  1.,  1.]]],


         [[[-0., -0., -0.],
           [-0., -0., -0.],
           [-0., -0., -0.],
           ..., 
           [-0., -0., -0.],
           [-0., -0., -0.],
           [-0., -0., -0.]],

请注意,代码似乎正确地使用了一个简单的,如:

代码语言:javascript
复制
def create_base():
    input_layer=Input(IMG_SIZE)
    base_model=Flatten()(input_layer)
    base_model=Dense(2048)(base_model)
    base_model=Model(input_layer,base_model)
    return base_model

在这方面,我已经用尽了大部分在线资源。这个问题的排列已经在Keras的github上被问到了,比如这里这里这里,但是我似乎找不到任何具体的解决方案。

链接表明,这些问题似乎源于将TimeDistributed应用于BatchNormalization的组合,而Lambda标识层或重塑层的黑客修复则消除了错误,但似乎没有输出正确的模型。

我试图通过以下方式强制基本模型支持掩蔽:

代码语言:javascript
复制
base_model.__setattr__('supports_masking',True)

我还尝试通过以下方式应用身份层:

代码语言:javascript
复制
TimeDistributed(Lambda(lambda x: base_model(x), output_shape=lambda s:s))(final_model)

但这些似乎都不起作用。请注意,我希望最后的模式是可培训的,特别是CNN部分应该保持可培训。

EN

回答 3

Stack Overflow用户

发布于 2018-05-07 12:29:22

不完全确定这是否有效,但基于在此发表的评论,使用较新版本的tensorflow + keras,它应该可以工作:

代码语言:javascript
复制
final_model = TimeDistributed(Flatten())(final_input)
final_model = Masking(mask_value = -2.)(final_model)
final_model = TimeDistributed(Reshape(IMG_SIZE))(final_model)
final_model = TimeDistributed(base_model)(final_model)
final_model = Model(final_input,final_model)

我看了一下掩蔽的源代码,我注意到Keras创建了一个只缩小最后一个轴的掩码张量。只要你处理的是5D张量,它就不会引起任何问题,但是当你减少LSTM的尺寸时,这个掩蔽张量就变得不相容了。

在掩蔽之前,做第一个扁平步骤,将确保掩蔽张量对三维张量正常工作。然后再将图像扩展到原来的大小。

我可能很快就会尝试安装新版本来亲自测试它,但是这些安装过程已经造成了太多的麻烦,我在这里遇到了一些重要的问题。

在我的机器上,这段代码会编译,但是这个奇怪的错误会出现在预测时间(参见这个答案第一行的链接)。

建立预测中间层的模型

根据我看到的代码,我不确定掩蔽函数是否在内部保持在张量中。我不知道它到底是如何工作的,但它似乎与层内函数的构建是分开管理的。

因此,尝试使用keras标准模型来进行预测:

代码语言:javascript
复制
inp = final_model.input                                           # input placeholder
outputs = [layer.output for layer in final_model.layers]          # all layer outputs

fullModel = Model(inp,outputs)
layerPredictions = fullModel.predict(np.expand_dims(TEST_SAMPLE,0))

print(layerPredictions[-2])
票数 3
EN

Stack Overflow用户

发布于 2018-05-09 19:42:56

它似乎是按预期运作的。Keras中的掩蔽不会像您预期的那样产生零,而是跳过上游层(如LSTM和损失计算)中屏蔽的时间步骤。在RNN的情况下,Keras (至少是tensorflow)被实现,从而将前一步的状态传递给backend.py。这在一定程度上是为了在动态输入时保持张量的形状。

如果您真的想要零,那么您必须使用与掩蔽和返回零类似的逻辑来实现自己的层。为了解决您的问题,您需要在使用final_input的最终LSTM层之前使用一个掩码。

代码语言:javascript
复制
class MyMask(Masking):
   """Layer that adds a mask based on initial input."""
   def compute_mask(self, inputs, mask=None):
      # Might need to adjust shapes
      return K.any(K.not_equal(inputs[0], self.mask_value), axis=-1)

   def call(self, inputs):
      # We just return input back
      return inputs[1]

   def compute_output_shape(self, input_shape):
     return input_shape[1]
final_model = MyMask(mask_value=-2.)([final_input, final_model])

您可能可以以更简单的方式附加掩码,但是这个自定义类实际上是根据初始输入添加了一个掩码,并输出了现在有掩码的Keras张量。

在您的示例中,LSTM将忽略第二个图像。要确认您可以return_sequences=True,并检查两个图像的输出是否相同。

票数 3
EN

Stack Overflow用户

发布于 2018-08-21 19:37:51

我正在尝试实现同样的东西,我希望我的LSTM序列有可变的大小。然而,我甚至不能实现你的原始模型。我得到以下错误: TypeError: input_1不支持掩蔽,但是传递了一个input_mask:张量(“time_distributed_1/repe1:0”,shape=(?,100,100),dtype=bool) --我使用的是tensorflow 1.10和keras 2.2.2。

我通过添加第二个输入,一个掩码来指定LSTM需要考虑的时间步骤来解决这个问题。这样,图像序列总是具有相同的时间步数,CNN总是生成一个输出,但是对于LSTM输入,其中一些步骤被忽略。但是,需要仔细选择丢失的图像,这样才不会影响批处理规范化。

代码语言:javascript
复制
def LSTM_CNN(params):
resnet = ResNet50(include_top=False, weights='imagenet', pooling = 'avg')
input_layer = Input(shape=(params.numFrames, params.height, params.width, 3))
input_mask = Input(shape=(params.numFrames,1))
curr_layer = TimeDistributed(resnet)(input_layer)    
resnetOutput = Dropout(0.5)(curr_layer)
curr_layer = multiply([resnetOutput,input_mask])
cnn_output = curr_layer
curr_layer = Masking(mask_value=0.0)(curr_layer)
lstm_out = LSTM(256, dropout=0.5)(curr_layer)
output = Dense(output_dim=params.numClasses, activation='sigmoid')(lstm_out)
model = Model([input_layer, input_mask], output)
return model
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50094633

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档