How is this layers of Keras in Pytorch?

Hello community.

I am writting a keras model into Pytorch but i have a big trouble with creating in pytorch this 3 keras layers

MaxPooling2D(pool_size=(2, 2), strides=(1, 1), padding='same')
MaxPooling2D(pool_size=(3, 3), padding='same', strides=(2, 2))
Conv2D(filters=12, kernel_size=(3, 3), activation='relu', padding='same', strides=(2, 2))

For the first one, i have fund that

x = torch.nn.MaxPool2d(kernel_size=3, stride=1, padding=1)(x)
x = [:, :, 1:, 1:]

gives a correct result, I got the same as using keras model.

For the las one i have used this wrapped and it works

class Conv2dSamePadding(nn.Conv2d):
    def __init__(self,*args,**kwargs):
        super(Conv2dSamePadding, self).__init__(*args, **kwargs)
        self.zero_pad_2d = nn.ZeroPad2d(reduce(__add__,
            [(k // 2 + (k - 2 * (k // 2)) - 1, k // 2) for k in self.kernel_size[::-1]]))

But can not with the second maxpooling.

Also i would appreciate a better general solution to my problem to solver the ‘padding issue’

Thanks

Sorry I have not use keras but do you try nn.Conv2d(xxx, ceil_mode=True) ?

1 Like

The implementation

class MaxPool2dSamePadding(nn.MaxPool2d):
    def __init__(self, *args,**kwargs):
        super().__init__(*args, **kwargs)

    def forward(self, input):
        in_height, in_width = input.shape[2:]

        if type(self.stride) is not tuple:
            self.stride = (self.stride, self.stride)
        if type(self.kernel_size) is not tuple:
            self.kernel_size = (self.kernel_size, self.kernel_size)

        if (in_height % self.stride[0] == 0):
            pad_along_height = max(self.kernel_size[0] - self.stride[0], 0)
        else:
            pad_along_height = max(self.kernel_size[0] - (in_height % self.stride[0]), 0)
        if (in_width % self.stride[1] == 0):
            pad_along_width = max(self.kernel_size[1] - self.stride[1], 0)
        else:
            pad_along_width = max(self.kernel_size[1] - (in_width % self.stride[1]), 0)

        pad_top = pad_along_height // 2
        pad_bottom = pad_along_height - pad_top
        pad_left = pad_along_width // 2
        pad_right = pad_along_width - pad_left

        input = F.pad(input, (pad_left, pad_right, pad_top, pad_bottom), value = float('-inf'))
        self.padding = (0, 0) # We did padding in the lane before. Force it to 0 by user

        return F.max_pool2d(input, self.kernel_size, self.stride,
                            self.padding, self.dilation, self.ceil_mode,
                            self.return_indices)


class AvgPool2dSamePadding(nn.AvgPool2d):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def forward(self, input):
        in_height, in_width = input.shape[2:]

        if type(self.stride) is not tuple:
            self.stride = (self.stride, self.stride)
        if type(self.kernel_size) is not tuple:
            self.kernel_size = (self.kernel_size, self.kernel_size)

        if (in_height % self.stride[0] == 0):
            pad_along_height = max(self.kernel_size[0] - self.stride[0], 0)
        else:
            pad_along_height = max(self.kernel_size[0] - (in_height % self.stride[0]), 0)
        if (in_width % self.stride[1] == 0):
            pad_along_width = max(self.kernel_size[1] - self.stride[1], 0)
        else:
            pad_along_width = max(self.kernel_size[1] - (in_width % self.stride[1]), 0)

        pad_top = pad_along_height // 2
        pad_bottom = pad_along_height - pad_top
        pad_left = pad_along_width // 2
        pad_right = pad_along_width - pad_left

        input = F.pad(input, (pad_left, pad_right, pad_top, pad_bottom), value=0.0)
        self.padding = (0, 0)  # We did padding in the lane before. Force it to 0 by user

        return F.avg_pool2d(input, self.kernel_size, self.stride,
                            self.padding, self.ceil_mode, self.count_include_pad, self.divisor_override)

class Conv2dSamePadding(nn.Conv2d):
    def __init__(self, *args,**kwargs):
        super().__init__(*args, **kwargs)

    def forward(self, input):
        in_height, in_width = input.shape[2:]

        if type(self.stride) is not tuple:
            self.stride = tuple(self.stride)
        if type(self.kernel_size) is not tuple:
            self.kernel_size = tuple(self.kernel_size)

        if (in_height % self.stride[0] == 0):
            pad_along_height = max(self.kernel_size[0] - self.stride[0], 0)
        else:
            pad_along_height = max(self.kernel_size[0] - (in_height % self.stride[0]), 0)
        if (in_width % self.stride[1] == 0):
            pad_along_width = max(self.kernel_size[1] - self.stride[1], 0)
        else:
            pad_along_width = max(self.kernel_size[1] - (in_width % self.stride[1]), 0)

        pad_top = pad_along_height // 2
        pad_bottom = pad_along_height - pad_top
        pad_left = pad_along_width // 2
        pad_right = pad_along_width - pad_left

        input = F.pad(input, (pad_left, pad_right, pad_top, pad_bottom), value=0.0)

        self.padding = (0, 0)  # We did padding in the lane before. Force it to 0 by user

        return  self._conv_forward(input, self.weight, self.bias)


I hope this can help someone. This is based on the source code of TensorFlow.