Search code examples
tf.kerasconv-neural-networksobel

How to construct a sobel filter for kernel initialization in input layer for images of size 128x128x3?


This is my code for sobel filter:

def init_f(shape, dtype=None):

    sobel_x = tf.constant([[-5, -4, 0, 4, 5], [-8, -10, 0, 10, 8], [-10, -20, 0, 20, 10], [-8, -10, 0, 10, 8], [-5, -4, 0, 4, 5]])

    ker = np.zeros(shape, dtype)
    ker_shape = tf.shape(ker)
    kernel = tf.tile(sobel_x, ker_shape)//*Is this correct?*
    return kernel

model.add(Conv2D(filters=30, kernel_size=(5,5), kernel_initializer=init_f, strides=(1,1), activation='relu'))

So far I have managed to do this. But, this gives me error:

Shape must be rank 2 but is rank 4 for 'conv2d_17/Tile' (op: 'Tile') with input shapes: [5,5], [4].

Tensorflow Version: 2.1.0


Solution

  • You're close, but the args to tile don't appear to be correct. That is why you're getting the error "Shape must be rank 2 but is rank 4 for..." You're sobel_x must be a rank 4 tensor, so you need to add two more dimensions. I used reshape in this example.

    from tensorflow import keras
    import tensorflow as tf
    import numpy
    
    def kernelInitializer(shape, dtype=None):
        print(shape)    
        sobel_x = tf.constant(
            [
                [-5, -4, 0, 4, 5], 
                [-8, -10, 0, 10, 8], 
                [-10, -20, 0, 20, 10], 
                [-8, -10, 0, 10, 8], 
                [-5, -4, 0, 4, 5]
            ], dtype=dtype )
        #create the missing dims.
        sobel_x = tf.reshape(sobel_x, (5, 5, 1, 1))
    
        print(tf.shape(sobel_x))
        #tile the last 2 axis to get the expected dims.
        sobel_x = tf.tile(sobel_x, (1, 1, shape[-2],shape[-1]))
    
        print(tf.shape(sobel_x))
        return sobel_x
    
    x1 = keras.layers.Input((128, 128, 3))
    
    cvl = keras.layers.Conv2D(30, kernel_size=(5,5), kernel_initializer=kernelInitializer, strides=(2,2), activation='relu')
    
    model = keras.Sequential();
    model.add(x1)
    model.add(cvl)
    
    data = numpy.ones((1, 128, 128, 3))
    data[:, 0:64, 0:64, :] = 0
    
    pd = model.predict(data)
    print(pd.shape)
    
    d = pd[0, :, :, 0]
    for row in d:
        for col in row:
            m = '0'
            if col != 0:
                m = 'X'
            print(m, end="")
        print("")
    

    I looked at using expand_dims instead of reshape but there didn't appear any advantage. broadcast_to seems ideal, but you still have to add the dimensions, so I don't think it was better than tile.

    Why 30 filters of the same filter though? Are they going to be changed afterwards?