изменить форму ядра сверточного слоя в керасе - PullRequest
1 голос
/ 29 апреля 2020

если у меня размер ядра 3X3, он будет смотреть на один пиксель вокруг пикселя, на котором он сфокусирован. например, для ядра:

1  2  3
4  5  6
7  8  9

оно будет использовать 1-9 для получения значения в местоположении 5 на карте объектов. Есть ли способ сделать так, чтобы он производил значение в местоположении 9? поэтому для каждого местоположения на карте объектов он будет «видеть» только пиксели сверху и слева от него?

в кератах, бэкэнд тензор потока.

РЕДАКТИРОВАТЬ: на основе ответа I получил, я использую следующий код:

from keras.layers import Layer
class CornerConv2D(Layer):
    def __init__(self, filters, **kwargs):
        self.filters = filters
        self.kernel_size = (3,3)
        super(CornerConv2D, self).__init__(**kwargs)

    def build(self, input_shape):
        shape = self.kernel_size + (input_shape[-1], self.filters)
        self.kernel = self.add_weight(name='kernel', shape=shape,
                                  initializer='glorot_uniform')
        super(CornerConv2D, self).build(input_shape)

    def call(self, layer_input):

        custom_kernel = K.get_value(self.kernel)
        # set the bottom right corner as zero
        custom_kernel[-1,-1,:,:] = np.zeros_like(custom_kernel[-1,-1,:,:])

        return K.conv2d(layer_input,  custom_kernel)

    def compute_output_shape(self, input_shape):
        return (input_shape[0], input_shape[1]-2, input_shape[1]-2) + (self.filters,)


inp = Input(shape=(64,64,1))
x = ZeroPadding2D(1)(inp)
x = CornerConv2D(30)(x)
x = ZeroPadding2D(1)(x)
x = CornerConv2D(30)(x)
x = ZeroPadding2D(1)(x)
x = CornerConv2D(1)(x)


m = Model(inputs=[inp], outputs=[x])

m.compile(loss='mse', optimizer="adam")

m.summary()

все еще есть проблема с этим. в то время как модель создается без проблем и может предсказывать без каких-либо ошибок, когда я пытаюсь обучить ее:

m.fit(imgs, imgs, batch_size=32, epochs=2)

выдает ошибку:

An operation has `None` for gradient. Please make sure that all of your ops have a gradient defined (i.e. are differentiable). Common ops without gradient: K.argmax, K.round, K.eval.

1 Ответ

2 голосов
/ 29 апреля 2020

Реализация собственного слоя, в котором вы манипулируете ядром, и применение дополнения нулями слева и сверху должны достичь того, что вы хотите:

             0  0  0  0 
1  2  3      0  1  2  3
4  5  6  ->  0  4  5  6 
7  8  9      0  7  8  9

И ядро ​​примет во внимание:

f  f
f  0

Для для позиции 4 он будет учитывать только 1, для позиции 5 - 1,2,4, а для позиции 9 - 5,6,8. Вы можете возиться с набивкой, как вы будете sh.

from tensorflow.keras.layers import ZeroPadding2D
from tensorflow.keras.models import Sequential
from tensorflow.keras import backend as K
import numpy as np

class CornerConv2D(Layer):
    def __init__(self, filters, **kwargs):
        self.filters = filters
        self.kernel_size = (2,2)
        super(CornerConv2D, self).__init__(**kwargs)

    def build(self, input_shape):
        shape = self.kernel_size + (input_shape[-1], self.filters)
        self.kernel = self.add_weight(name='kernel', shape=shape,
                                  initializer='glorot_uniform')
        super(CornerConv2D, self).build(input_shape)


    def call(self, layer_input):

        custom_kernel = K.get_value(self.kernel)
        # set the bottom right corner as zero
        custom_kernel[-1,-1,:,:] = np.zeros_like(custom_kernel[-1,-1,:,:])

        K.set_value(self.kernel, custom_kernel)
        return K.conv2d(layer_input,  self.kernel)


    def compute_output_shape(self, input_shape):
        return input_shape[:-1] + (self.filters,)


m = Sequential()
m.add(ZeroPadding2D(((1, 0), (1, 0) ), input_shape=(9,9,3))) # (1, 0), (1, 0) adds zeros to top and left
m.add(CornerConv2D(5)) # Valid padding as default

m.compile(loss='mse', optimizer="adam")

m.summary()
input_test = np.random.random((9,9,3))
pred = m.predict(input_test.reshape(1,9,9,3))

print(pred.shape)
...