在 Pytorch 中实现 SeparableConv2D

Implement SeparableConv2D in Pytorch

主要objective

SeparableConv2D 的 PyTorch 等价物 padding = 'same':

from tensorflow.keras.layers import SeparableConv2D
x = SeparableConv2D(64, (1, 16), use_bias = False, padding = 'same')(x)

SeparableConv2D 的 PyTorch 等价物是什么?

这个source说:

If groups = nInputPlane, kernel=(K, 1), (and before is a Conv2d layer with groups=1 and kernel=(1, K)), then it is separable.

虽然这个 source 说:

Its core idea is to break down a complete convolutional acid into a two-step calculation, Depthwise Convolution and Pointwise.

这是我的尝试:

class SeparableConv2d(nn.Module):
    def __init__(self, in_channels, out_channels, depth, kernel_size, bias=False):
        super(SeparableConv2d, self).__init__()
        self.depthwise = nn.Conv2d(in_channels, out_channels*depth, kernel_size=kernel_size, groups=in_channels, bias=bias)
        self.pointwise = nn.Conv2d(out_channels*depth, out_channels, kernel_size=1, bias=bias)

    def forward(self, x):
        out = self.depthwise(x)
        out = self.pointwise(out)
        return out

这是正确的吗?这是否等同于 tensorflow.keras.layers.SeparableConv2D

padding = 'same'呢?

执行此操作时如何确保我的输入和输出大小相同?

我的尝试:

x = F.pad(x, (8, 7, 0, 0), )

因为内核大小是(1,16),所以我添加了左右填充,分别为8和7。这是实现 padding = 'same' 的正确方法(也是最佳方法)吗?我怎样才能把它放在我的 SeparableConv2d class 中,并在给定输入数据维度大小的情况下即时计算?

一起

class SeparableConv2d(nn.Module):
    def __init__(self, in_channels, out_channels, depth, kernel_size, bias=False):
        super(SeparableConv2d, self).__init__()
        self.depthwise = nn.Conv2d(in_channels, out_channels*depth, kernel_size=kernel_size, groups=in_channels, bias=bias)
        self.pointwise = nn.Conv2d(out_channels*depth, out_channels, kernel_size=1, bias=bias)

    def forward(self, x):
        out = self.depthwise(x)
        out = self.pointwise(out)
        return out


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.separable_conv = SeparableConv2d(
            in_channels=32, 
            out_channels=64, 
            depth=1, 
            kernel_size=(1,16)
        )
        
    def forward(self, x):
        x = F.pad(x, (8, 7, 0, 0), )
        x = self.separable_conv(x)
        return x

这些代码有问题吗?

链接的定义大体一致。最好的一个在 article.

  • “Depthwise”(不是一个非常直观的名称,因为不涉及深度)- 是一系列规则的二维卷积,仅分别应用于数据层。 - "Pointwise" 与具有 1x1 内核的 Conv2d 相同。

我建议对您的 SeparableConv2d 进行一些更正 class:

  • 无需使用深度参数 - 与 out_channels
  • 相同
  • 我将填充设置为 1 以确保与 kernel=(3,3) 相同的输出大小。如果内核大小不同 - 使用与常规 Conv2d 相同的原则相应地调整填充。您的示例 class Net() 不再需要 - 填充在 SeparableConv2d.
  • 中完成

这是更新后的代码,应该类似于tf.keras.layers.SeparableConv2D实现:

class SeparableConv2d(nn.Module):

def __init__(self, in_channels, out_channels, kernel_size, bias=False):
    super(SeparableConv2d, self).__init__()
    self.depthwise = nn.Conv2d(in_channels, in_channels, kernel_size=kernel_size, 
                               groups=in_channels, bias=bias, padding=1)
    self.pointwise = nn.Conv2d(in_channels, out_channels, 
                               kernel_size=1, bias=bias)

def forward(self, x):
    out = self.depthwise(x)
    out = self.pointwise(out)
    return out