2017-06-28 25 views
1

我想将前一层的各个内核输出馈入一个新的转换过滤器,以获得下一层。为此,我尝试通过Conv2D传递每个内核输出,并通过索引来调用它们。我使用的功能是:Keras:将前一层的一部分送到下一层,在CNN中

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层的渔政船的要求。任何帮助解决这个问题将深受赞赏!

+0

您是否尝试过传递'x [i:i + 1]'? ---好奇心....你想用这个模型做什么? –

+0

那么,'x [i:i + 1]'将对应2个内核输出,对,而不是1?另外,'x'的维数变成'(None,5,224,224)'而不是'(5,224,224)'。关于为什么我尝试了它,我试图学习Conv Nets的实现,并试图用keras探索不同的东西,并陷入了困境。 – Prabaha

+0

'x [i:i + 1]'只返回一个元素,即'i'处的元素,但它作为数组/张量而不是单个元素返回。 (无论如何,它不工作)。 - 现在,'(无,.....)'是正常的。 Keras创建none来表示“batch_size”(你有多少个例子)。 - 如果你正在学习,我建议你不要这样做。除非你有明确的理由这么做,否则这不是任何人通常会做的事情。只需使用一个Conv2D图层,它将处理所有内容:'out = Conv2D(filters,.....)(x)' –

回答

2

在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图层不能有可训练的权重。

+0

对于那些使用“theano”后端的人,在Lambda层中添加'output_shape =(width,heigth,1)'参数。 –

1

Prabaha。我知道你已经解决了你的问题,但是现在我看到了你的答案,你可以在不使用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) 

你可以在你的答案,在这个答案比较计算总参数。

+1

这正是我一直在使用的实现。但是对于第一批'k'过滤器,我想加载预先训练好的权重,这可以通过'load_weights'中的'by_name = True'标志来完成。通过将一层'k'滤波器分成一个滤波器的'k'层,我没有一种方便的方式来加载预先训练好的权重。这就是为什么我必须提出一些保持层'x'完好的东西。 – Prabaha

相关问题