How to do custom convolutional layer in keras

Viewed 318

In Keras I need a custom convolutional neural network, where input 6x6 and output 2x2. How to do this? ( Maybe with custom layer )

I have created numpy example ( bad and slow code ):

import numpy as np
from matplotlib import image as mpimg, pyplot as plt
import json

def sigmoid(x, deriv=False):
    if deriv:
        return sigmoid(x)*(1-sigmoid(x))
    return 1/(1+np.exp(-x))

def read_rect(arr, x, y, w, h):
    new_arr = np.zeros((w, h, arr.shape[2]))
    for pix_x in range(w):
        for pix_y in range(h):
            if x+pix_x >= arr.shape[0] or y+pix_y >= arr.shape[1] or x+pix_x < 0 or y+pix_y < 0:
                pass
            else:
                new_arr[pix_x, pix_y] = arr[x+pix_x, y+pix_y]
    return new_arr
    return arr[x:x+w, y:y+w]

def write_rect(arr, dat, x, y):
    new_arr = arr.copy()
    for pix_x in range(dat.shape[0]):
        for pix_y in range(dat.shape[1]):
            if x+pix_x >= new_arr.shape[0] or y+pix_y >= new_arr.shape[1]:
                pass
            else:
                new_arr[x+pix_x, y+pix_y] = dat[pix_x, pix_y]
    return new_arr

def size(l):
    l = np.array(l)
    r = 1
    for i in l.ravel():
        r *= i
    return r

class UpConv2D:
    def __init__(self, kernel_in = (10, 10, 3), kernel_out = (2, 2, 3), activation=sigmoid):
        self.kernel_in = kernel_in[:3]
        self.kernel_out = kernel_out[:3]
        self.weights = 2*np.random.random((size(self.kernel_in),size(self.kernel_out))) - 1
        self.activation = activation

    def do_pixel(self, inp):
        inp = inp.ravel()[:size(self.kernel_in)]
        out = self.activation(np.dot(inp,self.weights))
        return np.array(out.reshape(self.kernel_out))
    def call(self, inp):
        out = np.zeros(np.append(np.array(inp.shape[:2])*self.kernel_out[:2], self.kernel_out[2]))
        for x in range(inp.shape[0]):
            for y in range(inp.shape[1]):
                square_in = read_rect(inp, x-self.kernel_in[0]//2, y-self.kernel_in[1]//2, self.kernel_in[0], self.kernel_in[1])
                square_out = self.do_pixel(square_in)
                out = write_rect(out, square_out, x*self.kernel_out[0], y*self.kernel_out[1])
        return out
    def __call__(self, *args, **kwargs):
        return self.call(*args, **kwargs)

    def write_weights(self):
        return json.dumps(self.weights.tolist())
    def read_weights(self, data):
        self.weights = numpy.array(json.loads(data))

I need to make it for Keras. If kernel_out is (5, 6, 3) and inp is (100, 120, 3), then shape of output image will be (5x100, 6x120, 3) or (500, 720, 3). So I create empty ( zeros ) matrix with spae (500, 720, 3) and I fill that while scanning. Do_pixel is simple one layer neural network with input kernel_in and output kernel_out. Read_rect - get rectangle from image. Write_rect - write rectangle in image. It is something like upscale convolutional layer

1 Answers

if input is 6x6 and ouptut should be 2x2, I believe you need simple convolution:

Conv2D(filter_num, kernel_size=(3,3), strides=(3,3), padding='valid', activation='relu')

Do not forget that input is 4D as from docs:

4+D tensor with shape: batch_shape + (channels, rows, cols) if data_format='channels_first' or 4+D tensor with shape: batch_shape + (rows, cols, channels) if data_format='channels_last'.

Related