【问题标题】:Keras: Feeding in part of previous layer to next layer, in CNNKeras:在 CNN 中将前一层的一部分馈送到下一层
【发布时间】:2017-12-02 05:12:48
【问题描述】:

我正在尝试将前一层的单个内核输出馈送到一个新的 conv 过滤器,以获得下一层。为此,我尝试通过Conv2D 传递每个内核输出,通过它们的索引调用它们。我使用的函数是:

def modification(weights_path=None, classes=2):

    ###########
    ## Input ##
    ###########

    ### 224x224x3 sized RGB Input
    inputs = Input(shape=(224,224,3))

    #################################
    ## Conv2D Layer with 5 kernels ##
    #################################

    k = 5
    x = Conv2D(k, (3,3), data_format='channels_last', padding='same', name='block1_conv1')(inputs)
    y = np.empty(k, dtype=object)
    for i in range(0,k):
        y[i] = Conv2D(1, (3,3), data_format='channels_last', padding='same')(np.asarray([x[i]]))
    y = keras.layers.concatenate([y[i] for i in range (0,k)], axis=3, name='block1_conv1_loc')
    out = Activation('relu')(y)
    print ('Output shape is, ' +str(out.get_shape()))

    ### Maxpooling(2,2) with a stride of (2,2)
    out = MaxPooling2D((2,2), strides=(2,2), data_format='channels_last')(out)

    ############################################
    ## Top layer, with fully connected layers ##
    ############################################

    out = Flatten(name='flatten')(out)
    out = Dense(4096, activation='relu', name='fc1')(out)
    out = Dropout(0.5)(out)
    out = Dense(4096, activation='relu', name='fc2')(out)
    out = Dropout(0.5)(out)
    out = Dense(classes, activation='softmax', name='predictions')(out)

    if weights_path:
        model.load_weights(weights_path)

    model = Model(inputs, out, name='modification')

    return model

但这不起作用,并引发以下错误:

Traceback (most recent call last):
  File "sim-conn-edit.py", line 137, in <module>
    model = modification()
  File "sim-conn-edit.py", line 38, in modification
    y[i] = Conv2D(1, (3,3), data_format='channels_last', padding='same')(np.asarray([x[i]]))
  File "/home/yx96/anaconda2/lib/python2.7/site-packages/keras/engine/topology.py", line 511, in __call__
    self.assert_input_compatibility(inputs)
  File "/home/yx96/anaconda2/lib/python2.7/site-packages/keras/engine/topology.py", line 408, in assert_input_compatibil
ity
    if K.ndim(x) != spec.ndim:
  File "/home/yx96/anaconda2/lib/python2.7/site-packages/keras/backend/tensorflow_backend.py", line 437, in ndim
    dims = x.get_shape()._dims
AttributeError: 'numpy.ndarray' object has no attribute 'get_shape'

我将x[i] 层输入为[ x[i] ] 以满足Conv2D 层的尺寸要求。任何解决此问题的帮助将不胜感激!

【问题讨论】:

  • 你试过只是传递x[i:i+1]吗? --- 好奇心......你想用那个模型做什么?
  • 嗯,x[i:i+1] 将对应 2 个内核输出,对,不是 1 个?此外,x 的维度原来是(None, 5, 224, 224) 而不是(5, 224, 224)。关于我为什么要尝试它,我正在尝试学习 Conv Nets 的实现,并尝试使用 keras 探索不同的东西,结果被困在这里。
  • x[i:i+1] 仅返回一个元素,即i 处的元素,但它以数组/张量而不是单个元素的形式返回。 (无论如何,它不起作用)。 -- 现在,(None, .....) 很正常。 Keras 创建 none 来表示“batch_size”(您有多少示例)。 - 而且,如果你正在学习,我建议你不要尝试这样做。除非您有非常明确的理由这样做,否则通常不会有人这样做。只需使用一个 Conv2D 层,它就会处理所有事情:out = Conv2D(filters,.....)(x)
  • 我不认为分离张量的部分是通常做的事情。如果你详细解释你想做什么,为什么需要分开零件以及你想要多少零件,也许我们可以找到另一种方法。
  • @Daniel 如果您给我您的电子邮件地址,我可以将问题的详细描述发送给您。

标签: python-2.7 keras conv-neural-network keras-layer


【解决方案1】:

在 StackOverflow 中发布了 thisthis 问题,并进行了一些个人探索后,我想出了一个解决方案。可以使用Lambda 层来做到这一点;通过调用Lambda 层来提取前一层的子部分。例如,如果Lambda函数定义为,

def layer_slice(x,i):
    return x[:,:,:,i:i+1]

然后,称为,

k = 5
x = Conv2D(k, (3,3), data_format='channels_last', padding='same', name='block1_conv1')(inputs)
y = np.empty(k, dtype=object)
for i in range(0,k):
    y[i] = Lambda(layer_slice, arguments={'i':i})(x)
    y[i] = Conv2D(1,(3,3), data_format='channels_last', padding='same')(y[i])
y = keras.layers.concatenate([y[i] for i in range (0,k)], axis=3, name='block1_conv1_loc')
out = Activation('relu')(y)
print ('Output shape is, ' +str(out.get_shape()))

它应该有效地将单个内核输出馈送到新的Conv2D 层。从model.summary() 获得的层形状和相应的可训练参数数量与预期相符。感谢Daniel 指出Lambda 层不能有可训练的权重。

【讨论】:

  • 对于那些使用“theano”后端的人,请在 Lambda 层中添加output_shape=(width,heigth,1) 参数。
【解决方案2】:

普拉巴哈。我知道你已经解决了你的问题,但现在我看到了你的答案,你也可以不使用 lambda 层来做到这一点,只需将第一个 Conv2D 拆分为多个。一层有 k 个过滤器相当于 k 层有一个过滤器:

for i in range(0,k):
    y[i] = Conv2D(1, (3,3), ... , name='block1_conv'+str(i))(inputs)     
    y[i] = Conv2D(1,(3,3), ...)(y[i])
y = Concatenate()([y[i] for i in range (0,k)])
out = Activation('relu')(y)

您可以计算答案和此答案中的总参数进行比较。

【讨论】:

  • 这正是我一直在使用的实现。但是对于第一组k 过滤器,我想加载预训练的权重,这可以通过load_weights 中的by_name=True 标志来完成。通过将一层k 过滤器分解为一个过滤器的k 层,我没有一种方便的方法来加载预训练的权重。这就是为什么,我必须想出一些东西来保持层 x 完好无损。
猜你喜欢
  • 2017-04-13
  • 1970-01-01
  • 2020-08-19
  • 1970-01-01
  • 1970-01-01
  • 2019-04-16
  • 2016-12-03
  • 1970-01-01
  • 2019-09-29
相关资源
最近更新 更多