Keras: подача в части предыдущего слоя к следующему слою, в CNN

Я пытаюсь передать отдельные выходы ядра предыдущего слоя в новый фильтр 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 слой. Любая помощь в решении этой проблемы будет высоко оценена!

2 ответа

Решение

После публикации этого и этого вопросов в Stackru и некоторых личных исследований я нашел решение. Можно, возможно, сделать это с 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 Möller за указание на то, что Lambda слои не могут иметь тренируемый вес.

Prabaha. Я знаю, что вы решили свою проблему, но теперь я вижу ваш ответ, вы можете сделать это без использования лямбда-слоя, просто разделив первый 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)

Вы можете посчитать итоговые параметры в своем ответе и в этом ответе сравнить.

Другие вопросы по тегам