pytorchでPSPNet(その1 ネットワークを作る[Pyramid Pooling])

書いてる理由

  • pytorchを基礎からもう一回

参考

pytorchによる発展ディープラーニング

https://arxiv.org/pdf/1612.01105.pdf

詳細

pytorch_work/network.py at master · ys201810/pytorch_work · GitHub

PSPNetでセマンティックセグメンテーションする。
昨日はFeature Mapを作る箇所だったので、今日はPyramid Poolingの箇所

f:id:raishi12:20200312221551p:plain

PSPNetは、上の画像の通り、inputの画像(a)をFeature Map(b)で特徴抽出して、Pyramid Pooling Moudle(c)で4つの異なるサイズのFeature Mapを元のFeature MAPの大きさにUpsamplingした上でconcatしてから予測する。
この(c)の箇所

# Pyramid Pooling
class PyramidPooling(nn.Module):
    def __init__(self, in_channels, pool_sizes, height, width):
        super(PyramidPooling, self).__init__()

        self.height = height
        self.width = width

        out_channels = int(in_channels / len(pool_sizes))

        self.avpool1 = nn.AdaptiveAvgPool2d(output_size=pool_sizes[0])
        self.cbr1 = Conv2DBatchNormRelu(in_channels, out_channels, kernel_size=1, stride=1, padding=0,
                                        dilation=1, bias=False)

        self.avpool2 = nn.AdaptiveAvgPool2d(output_size=pool_sizes[1])
        self.cbr2 = Conv2DBatchNormRelu(in_channels, out_channels, kernel_size=1, stride=1, padding=0,
                                        dilation=1, bias=False)

        self.avpool3 = nn.AdaptiveAvgPool2d(output_size=pool_sizes[2])
        self.cbr3 = Conv2DBatchNormRelu(in_channels, out_channels, kernel_size=1, stride=1, padding=0,
                                        dilation=1, bias=False)

        self.avpool4 = nn.AdaptiveAvgPool2d(output_size=pool_sizes[3])
        self.cbr4 = Conv2DBatchNormRelu(in_channels, out_channels, kernel_size=1, stride=1, padding=0,
                                        dilation=1, bias=False)

    def forward(self, x):
        out1 = self.cbr1(self.avpool1(x))
        out1 = F.interpolate(out1, size=(self.height, self.width), mode='bilinear', aligh_corners=True)

        out2 = self.cbr2(self.avpool2(x))
        out2 = F.interpolate(out2, size=(self.height, self.width), mode='bilinear', aligh_corners=True)

        out3 = self.cbr3(self.avpool3(x))
        out3 = F.interpolate(out3, size=(self.height, self.width), mode='bilinear', aligh_corners=True)

        out4 = self.cbr4(self.avpool4(x))
        out4 = F.interpolate(out4, size=(self.height, self.width), mode='bilinear', aligh_corners=True)

        output = torch.cat([x, out1, out2, out3, out4], dim=1)
        return output

Pyramid Poolingは、前の層で得た60 * 60 * 2048のFeature Mapを4つの異なるサイズで特徴抽出して、Pyramid Poolingのinputと同じサイズにUpsamplingしてconcatする。

AdaptiveAvgPool2dにoutput_sizeを指定すると、その縦横サイズでinputの次元数をもつ出力が得られる。
今欲しい4つのサイズが、6 * 6, 3*3, 2 * 2, 1 * 1なので、
nn.AdaptiveAvgPool2d(output_size=6)、nn.AdaptiveAvgPool2d(output_size=3)、nn.AdaptiveAvgPool2d(output_size=2)、nn.AdaptiveAvgPool2d(output_size=1)でそれぞれ実施後、Conv -> BatchNorm -> Reluをかけて、Upsamplingで 60 * 60に戻す。
UpsamplingはF.interpolateで実施する。
最後に、torch.cat([x, out1, out2, out3, out4], dim=1)でConcat。dim=1はchannel方向に結合を意味する。(batch_size, channel_size, height, widhtなので)
今日はここまで。次は、予測結果の出力箇所。