Menu

Helper Module for Deep Learning.

Source code for pynet.models.pspnet

# -*- coding: utf-8 -*-
##########################################################################
# NSAp - Copyright (C) CEA, 2020
# Distributed under the terms of the CeCILL-B license, as published by
# the CEA-CNRS-INRIA. Refer to the LICENSE file or to
# http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
# for details.
##########################################################################

"""
The Pyramid Scene Parsing Network.
"""

# Imports
import math
import logging
import collections
import torch
import torch.nn as nn
import torch.nn.functional as func
from pynet.interfaces import DeepLearningDecorator
from pynet.utils import Networks
import numpy as np


# Global parameters
logger = logging.getLogger("pynet")


[docs]@Networks.register @DeepLearningDecorator(family=("encoder", "segmenter")) class PSPNet(nn.Module): """ Pyramid Scene Parsing Network. Reference: https://arxiv.org/pdf/1612.01105.pdf Code: https://github.com/cv-lee/BraTs """
[docs] def __init__(self, n_classes=2, sizes=(1, 2, 3, 6), psp_size=2048, deep_features_size=1024, backend="resnet34", drop_rate=0): """ Init class. Parameters ---------- n_classes: int, default 2 the number of features in the output segmentation map. """ nn.Module.__init__(self) if backend == "resnet18": self.feats = resnet18(drop_rate) elif backend == "resnet34": self.feats = resnet34(drop_rate) elif backend == "resnet50": self.feats = resnet50(drop_rate) else: raise ValueError("Unsupported backend.") self.psp = PSPModule(psp_size, 1024, sizes) self.up1 = PSPUpsample(1024, 256, drop_rate) self.up2 = PSPUpsample(256, 64, drop_rate) self.up3 = PSPUpsample(64, 64, drop_rate) self.final = nn.Sequential( nn.Conv2d(64, n_classes, kernel_size=1), nn.LogSoftmax())
# self.classifier = nn.Sequential( # nn.Linear(deep_features_size, 256), # nn.ReLU(), # nn.Linear(256, n_classes))
[docs] def forward(self, x): logger.debug("PSPNet...") self.debug("input", x) # f, class_f = self.feats(x) f, _ = self.feats(x) self.debug("feats", f) p = self.psp(f) self.debug("psp", p) p = self.up1(p) self.debug("up1", p) p = self.up2(p) self.debug("up2", p) p = self.up3(p) self.debug("up3", p) # auxiliary = func.adaptive_max_pool2d( # input=class_f, output_size=(1, 1)).view(-1, class_f.size(1)) p = self.final(p) self.debug("final", p) # p = func.softmax(p, dim=1) logger.debug("Done.") return p # , self.classifier(auxiliary)
[docs] def debug(self, name, tensor): """ Print debug message. Parameters ---------- name: str the tensor name in the displayed message. tensor: Tensor a pytorch tensor. """ logger.debug(" {3}: {0} - {1} - {2}".format( tensor.shape, tensor.get_device(), tensor.dtype, name))
[docs]class PSPModule(nn.Module):
[docs] def __init__(self, features, out_features=1024, sizes=(1, 2, 3, 6), drop_rate=0): super(PSPModule, self).__init__() self.stages = [] self.stages = nn.ModuleList([ self._make_stage(features, size) for size in sizes]) self.bottleneck = nn.Conv2d(features * (len(sizes) + 1), out_features, kernel_size=1) self.relu = nn.ReLU()
def _make_stage(self, features, size): prior = nn.AdaptiveAvgPool2d(output_size=(size, size)) conv = nn.Conv2d(features, features, kernel_size=1, bias=False) return nn.Sequential(prior, conv)
[docs] def forward(self, feats): h, w = feats.size(2), feats.size(3) priors = [ func.interpolate(input=stage(feats), size=(h, w), mode="bilinear", align_corners=True) for stage in self.stages] priors += [feats] bottle = self.bottleneck(torch.cat(priors, 1)) return self.relu(bottle)
[docs]class PSPUpsample(nn.Module):
[docs] def __init__(self, in_channels, out_channels, drop_rate=0): super(PSPUpsample, self).__init__() self.conv = nn.Sequential( nn.Conv2d(in_channels, out_channels, 3, padding=1), nn.BatchNorm2d(out_channels), nn.Dropout2d(p=drop_rate), nn.PReLU() )
[docs] def forward(self, x): h, w = 2 * x.size(2), 2 * x.size(3) p = func.interpolate( input=x, size=(h, w), mode="bilinear", align_corners=True) return self.conv(p)
[docs]class ResNet(nn.Module): """ Implementation of dilated ResNet with deep supervision. Downsampling is changed to 8x. """
[docs] def __init__(self, block, layers=(3, 4, 23, 3), drop_rate=0): self.inplanes = 64 super(ResNet, self).__init__() self.conv1 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False) self.bn1 = nn.BatchNorm2d(64) self.relu = nn.ReLU(inplace=True) self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) self.layer1 = self._make_layer(block, 64, layers[0], drop_rate=drop_rate) self.layer2 = self._make_layer(block, 128, layers[1], stride=2, drop_rate=drop_rate) self.layer3 = self._make_layer(block, 256, layers[2], stride=1, dilation=2, drop_rate=drop_rate) self.layer4 = self._make_layer(block, 512, layers[3], stride=1, dilation=4, drop_rate=drop_rate) for m in self.modules(): if isinstance(m, nn.Conv2d): n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels m.weight.data.normal_(0, math.sqrt(2. / n)) elif isinstance(m, nn.BatchNorm2d): m.weight.data.fill_(1) m.bias.data.zero_()
def _make_layer(self, block, planes, blocks, stride=1, dilation=1, drop_rate=0): downsample = None if stride != 1 or self.inplanes != planes * block.expansion: downsample = nn.Sequential( nn.Conv2d(self.inplanes, planes * block.expansion, kernel_size=1, stride=stride, bias=False), nn.BatchNorm2d(planes * block.expansion), nn.Dropout2d(drop_rate) ) layers = [block(self.inplanes, planes, stride, downsample, drop_rate=drop_rate)] self.inplanes = planes * block.expansion for i in range(1, blocks): layers.append(block(self.inplanes, planes, dilation=dilation, drop_rate=drop_rate)) return nn.Sequential(*layers)
[docs] def forward(self, x): x = self.conv1(x) x = self.bn1(x) x = self.relu(x) x = self.maxpool(x) x = self.layer1(x) x = self.layer2(x) x_3 = self.layer3(x) x = self.layer4(x_3) return x, x_3
[docs]class BasicBlock(nn.Module): expansion = 1
[docs] def __init__(self, inplanes, planes, stride=1, downsample=None, dilation=1, drop_rate=0): super(BasicBlock, self).__init__() self.dp = nn.Dropout2d(p=drop_rate) self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=3, stride=stride, padding=dilation, dilation=dilation, bias=False) self.bn1 = nn.BatchNorm2d(planes) self.relu = nn.ReLU(inplace=True) self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=dilation, dilation=dilation, bias=False) self.bn2 = nn.BatchNorm2d(planes) self.downsample = downsample self.stride = stride
[docs] def forward(self, x): residual = x out = self.conv1(x) out = self.bn1(out) out = self.dp(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) # out = self.dp(out) # Bottom or Here if self.downsample is not None: residual = self.downsample(x) out += residual out = self.dp(out) out = self.relu(out) return out
[docs]class Bottleneck(nn.Module): expansion = 4
[docs] def __init__(self, inplanes, planes, stride=1, downsample=None, dilation=1, drop_rate=0): super(Bottleneck, self).__init__() self.dp = nn.Dropout2d(p=drop_rate) self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) self.bn1 = nn.BatchNorm2d(planes) self.conv2 = nn.Conv2d( planes, planes, kernel_size=3, stride=stride, dilation=dilation, padding=dilation, bias=False) self.bn2 = nn.BatchNorm2d(planes) self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) self.bn3 = nn.BatchNorm2d(planes * 4) self.relu = nn.ReLU(inplace=True) self.downsample = downsample self.stride = stride
[docs] def forward(self, x): residual = x out = self.conv1(x) out = self.bn1(out) out = self.dp(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) out = self.dp(out) out = self.relu(out) out = self.conv3(out) out = self.bn3(out) if self.downsample is not None: residual = self.downsample(x) out += residual out = self.dp(out) out = self.relu(out) return out
[docs]def resnet18(drop_rate=0): model = ResNet(BasicBlock, [2, 2, 2, 2], drop_rate=drop_rate) return model
[docs]def resnet34(drop_rate=0): model = ResNet(BasicBlock, [3, 4, 6, 3], drop_rate=drop_rate) return model
[docs]def resnet50(drop_rate=0): model = ResNet(Bottleneck, [3, 4, 6, 3], drop_rate=drop_rate) return model
[docs]def pspnet_res18(drop_rate=0): return PSPNet(sizes=(1, 2, 3, 6), psp_size=512, deep_features_size=256, backend="resnet18", drop_rate=drop_rate)
[docs]def pspnet_res34(drop_rate=0): return PSPNet(sizes=(1, 2, 3, 6), psp_size=512, deep_features_size=256, backend="resnet34", drop_rate=drop_rate)
[docs]def pspnet_res50(drop_rate=0): return PSPNet(sizes=(1, 2, 3, 6), psp_size=2048, deep_features_size=1024, backend="resnet50", drop_rate=drop_rate)

Follow us

© 2019, pynet developers .
Inspired by AZMIND template.