Download models/deeplabv3plus.py from PeCoLab/EchMo-Vis: direct link, hf CLI and curl.
- Browser
- Download file 20.7 kB
-
https://huggingface.co/PeCoLab/EchMo-Vis/resolve/main/models/deeplabv3plus.py
- Command line
-
hf download hf://PeCoLab/EchMo-Vis/models/deeplabv3plus.py
-
curl -L -o deeplabv3plus.py https://huggingface.co/PeCoLab/EchMo-Vis/resolve/main/models/deeplabv3plus.py
20.7 kB
| # from https://github.com/VainF/DeepLabV3Plus-Pytorch/tree/master | |
| import torch | |
| import torch.nn as nn | |
| from torch.nn import functional as F | |
| from collections import OrderedDict | |
| class IntermediateLayerGetter(nn.ModuleDict): | |
| """ | |
| Module wrapper that returns intermediate layers from a model | |
| It has a strong assumption that the modules have been registered | |
| into the model in the same order as they are used. | |
| This means that one should **not** reuse the same nn.Module | |
| twice in the forward if you want this to work. | |
| Additionally, it is only able to query submodules that are directly | |
| assigned to the model. So if `model` is passed, `model.feature1` can | |
| be returned, but not `model.feature1.layer2`. | |
| Arguments: | |
| model (nn.Module): model on which we will extract the features | |
| return_layers (Dict[name, new_name]): a dict containing the names | |
| of the modules for which the activations will be returned as | |
| the key of the dict, and the value of the dict is the name | |
| of the returned activation (which the user can specify). | |
| Examples:: | |
| >>> m = torchvision.models.resnet18(pretrained=True) | |
| >>> # extract layer1 and layer3, giving as names `feat1` and feat2` | |
| >>> new_m = torchvision.models._utils.IntermediateLayerGetter(m, | |
| >>> {'layer1': 'feat1', 'layer3': 'feat2'}) | |
| >>> out = new_m(torch.rand(1, 3, 224, 224)) | |
| >>> print([(k, v.shape) for k, v in out.items()]) | |
| >>> [('feat1', torch.Size([1, 64, 56, 56])), | |
| >>> ('feat2', torch.Size([1, 256, 14, 14]))] | |
| """ | |
| def __init__(self, model, return_layers, hrnet_flag=False): | |
| if not set(return_layers).issubset([name for name, _ in model.named_children()]): | |
| raise ValueError("return_layers are not present in model") | |
| self.hrnet_flag = hrnet_flag | |
| orig_return_layers = return_layers | |
| return_layers = {k: v for k, v in return_layers.items()} | |
| layers = OrderedDict() | |
| for name, module in model.named_children(): | |
| layers[name] = module | |
| if name in return_layers: | |
| del return_layers[name] | |
| if not return_layers: | |
| break | |
| super(IntermediateLayerGetter, self).__init__(layers) | |
| self.return_layers = orig_return_layers | |
| def forward(self, x): | |
| out = OrderedDict() | |
| for name, module in self.named_children(): | |
| if self.hrnet_flag and name.startswith('transition'): # if using hrnet, you need to take care of transition | |
| if name == 'transition1': # in transition1, you need to split the module to two streams first | |
| x = [trans(x) for trans in module] | |
| else: # all other transition is just an extra one stream split | |
| x.append(module(x[-1])) | |
| else: # other models (ex:resnet,mobilenet) are convolutions in series. | |
| x = module(x) | |
| if name in self.return_layers: | |
| out_name = self.return_layers[name] | |
| if name == 'stage4' and self.hrnet_flag: # In HRNetV2, we upsample and concat all outputs streams together | |
| output_h, output_w = x[0].size(2), x[0].size(3) # Upsample to size of highest resolution stream | |
| x1 = F.interpolate(x[1], size=(output_h, output_w), mode='bilinear', align_corners=False) | |
| x2 = F.interpolate(x[2], size=(output_h, output_w), mode='bilinear', align_corners=False) | |
| x3 = F.interpolate(x[3], size=(output_h, output_w), mode='bilinear', align_corners=False) | |
| x = torch.cat([x[0], x1, x2, x3], dim=1) | |
| out[out_name] = x | |
| else: | |
| out[out_name] = x | |
| return out | |
| class _SimpleSegmentationModel(nn.Module): | |
| def __init__(self, backbone, classifier): | |
| super(_SimpleSegmentationModel, self).__init__() | |
| self.backbone = backbone | |
| self.classifier = classifier | |
| # lt@20240406 reduce resolution | |
| # self.pool0 = nn.MaxPool2d(2, stride=2, ceil_mode=True) | |
| def forward(self, x): | |
| # lt@20240406 reduce resolution | |
| # x = self.pool0(x) | |
| # lt@20240408 add resolution | |
| # x = F.interpolate(x, scale_factor=2, mode='bilinear', align_corners=True) | |
| input_shape = x.shape[-2:] | |
| features = self.backbone(x) | |
| x = self.classifier(features) | |
| x = F.interpolate(x, size=input_shape, mode='bilinear', align_corners=False) | |
| # lt@20240406 recover resolution | |
| # x = F.interpolate(x, scale_factor=2, mode='bilinear', align_corners=True) | |
| # lt@20240408 add resolution | |
| # x = F.interpolate(x, scale_factor=0.5, mode='bilinear', align_corners=True) | |
| return x | |
| class DeepLabV3(_SimpleSegmentationModel): | |
| """ | |
| Implements DeepLabV3 model from | |
| `"Rethinking Atrous Convolution for Semantic Image Segmentation" | |
| <https://arxiv.org/abs/1706.05587>`_. | |
| Arguments: | |
| backbone (nn.Module): the network used to compute the features for the model. | |
| The backbone should return an OrderedDict[Tensor], with the key being | |
| "out" for the last feature map used, and "aux" if an auxiliary classifier | |
| is used. | |
| classifier (nn.Module): module that takes the "out" element returned from | |
| the backbone and returns a dense prediction. | |
| aux_classifier (nn.Module, optional): auxiliary classifier used during training | |
| """ | |
| pass | |
| class DeepLabHeadV3Plus(nn.Module): | |
| def __init__(self, in_channels, low_level_channels, num_classes, aspp_dilate=[12, 24, 36]): | |
| super(DeepLabHeadV3Plus, self).__init__() | |
| self.project = nn.Sequential( | |
| nn.Conv2d(low_level_channels, 48, 1, bias=False), | |
| nn.BatchNorm2d(48), | |
| nn.ReLU(inplace=True), | |
| ) | |
| self.aspp = ASPP(in_channels, aspp_dilate) | |
| self.classifier = nn.Sequential( | |
| nn.Conv2d(304, 256, 3, padding=1, bias=False), | |
| nn.BatchNorm2d(256), | |
| nn.ReLU(inplace=True), | |
| nn.Conv2d(256, num_classes, 1) | |
| ) | |
| self._init_weight() | |
| def forward(self, feature): | |
| low_level_feature = self.project( feature['low_level'] ) | |
| output_feature = self.aspp(feature['out']) | |
| output_feature = F.interpolate(output_feature, size=low_level_feature.shape[2:], mode='bilinear', align_corners=False) | |
| return self.classifier( torch.cat( [ low_level_feature, output_feature ], dim=1 ) ) | |
| def _init_weight(self): | |
| for m in self.modules(): | |
| if isinstance(m, nn.Conv2d): | |
| nn.init.kaiming_normal_(m.weight) | |
| elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): | |
| nn.init.constant_(m.weight, 1) | |
| nn.init.constant_(m.bias, 0) | |
| class DeepLabHead(nn.Module): | |
| def __init__(self, in_channels, num_classes, aspp_dilate=[12, 24, 36]): | |
| super(DeepLabHead, self).__init__() | |
| self.classifier = nn.Sequential( | |
| ASPP(in_channels, aspp_dilate), | |
| nn.Conv2d(256, 256, 3, padding=1, bias=False), | |
| nn.BatchNorm2d(256), | |
| nn.ReLU(inplace=True), | |
| nn.Conv2d(256, num_classes, 1) | |
| ) | |
| self._init_weight() | |
| def forward(self, feature): | |
| return self.classifier( feature['out'] ) | |
| def _init_weight(self): | |
| for m in self.modules(): | |
| if isinstance(m, nn.Conv2d): | |
| nn.init.kaiming_normal_(m.weight) | |
| elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): | |
| nn.init.constant_(m.weight, 1) | |
| nn.init.constant_(m.bias, 0) | |
| class AtrousSeparableConvolution(nn.Module): | |
| """ Atrous Separable Convolution | |
| """ | |
| def __init__(self, in_channels, out_channels, kernel_size, | |
| stride=1, padding=0, dilation=1, bias=True): | |
| super(AtrousSeparableConvolution, self).__init__() | |
| self.body = nn.Sequential( | |
| # Separable Conv | |
| nn.Conv2d( in_channels, in_channels, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, bias=bias, groups=in_channels ), | |
| # PointWise Conv | |
| nn.Conv2d( in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=bias), | |
| ) | |
| self._init_weight() | |
| def forward(self, x): | |
| return self.body(x) | |
| def _init_weight(self): | |
| for m in self.modules(): | |
| if isinstance(m, nn.Conv2d): | |
| nn.init.kaiming_normal_(m.weight) | |
| elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): | |
| nn.init.constant_(m.weight, 1) | |
| nn.init.constant_(m.bias, 0) | |
| class ASPPConv(nn.Sequential): | |
| def __init__(self, in_channels, out_channels, dilation): | |
| modules = [ | |
| nn.Conv2d(in_channels, out_channels, 3, padding=dilation, dilation=dilation, bias=False), | |
| nn.BatchNorm2d(out_channels), | |
| nn.ReLU(inplace=True) | |
| ] | |
| super(ASPPConv, self).__init__(*modules) | |
| class ASPPPooling(nn.Sequential): | |
| def __init__(self, in_channels, out_channels): | |
| super(ASPPPooling, self).__init__( | |
| nn.AdaptiveAvgPool2d(1), | |
| nn.Conv2d(in_channels, out_channels, 1, bias=False), | |
| nn.BatchNorm2d(out_channels), | |
| nn.ReLU(inplace=True)) | |
| def forward(self, x): | |
| size = x.shape[-2:] | |
| x = super(ASPPPooling, self).forward(x) | |
| return F.interpolate(x, size=size, mode='bilinear', align_corners=False) | |
| class ASPP(nn.Module): | |
| def __init__(self, in_channels, atrous_rates): | |
| super(ASPP, self).__init__() | |
| out_channels = 256 | |
| modules = [] | |
| modules.append(nn.Sequential( | |
| nn.Conv2d(in_channels, out_channels, 1, bias=False), | |
| nn.BatchNorm2d(out_channels), | |
| nn.ReLU(inplace=True))) | |
| rate1, rate2, rate3 = tuple(atrous_rates) | |
| modules.append(ASPPConv(in_channels, out_channels, rate1)) | |
| modules.append(ASPPConv(in_channels, out_channels, rate2)) | |
| modules.append(ASPPConv(in_channels, out_channels, rate3)) | |
| modules.append(ASPPPooling(in_channels, out_channels)) | |
| self.convs = nn.ModuleList(modules) | |
| self.project = nn.Sequential( | |
| nn.Conv2d(5 * out_channels, out_channels, 1, bias=False), | |
| nn.BatchNorm2d(out_channels), | |
| nn.ReLU(inplace=True), | |
| nn.Dropout(0.1),) | |
| def forward(self, x): | |
| res = [] | |
| for conv in self.convs: | |
| res.append(conv(x)) | |
| res = torch.cat(res, dim=1) | |
| return self.project(res) | |
| def convert_to_separable_conv(module): | |
| new_module = module | |
| if isinstance(module, nn.Conv2d) and module.kernel_size[0]>1: | |
| new_module = AtrousSeparableConvolution(module.in_channels, | |
| module.out_channels, | |
| module.kernel_size, | |
| module.stride, | |
| module.padding, | |
| module.dilation, | |
| module.bias) | |
| for name, child in module.named_children(): | |
| new_module.add_module(name, convert_to_separable_conv(child)) | |
| return new_module | |
| def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1): | |
| """3x3 convolution with padding""" | |
| return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, | |
| padding=dilation, groups=groups, bias=False, dilation=dilation) | |
| def conv1x1(in_planes, out_planes, stride=1): | |
| """1x1 convolution""" | |
| return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False) | |
| class BasicBlock(nn.Module): | |
| expansion = 1 | |
| def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1, | |
| base_width=64, dilation=1, norm_layer=None): | |
| super(BasicBlock, self).__init__() | |
| if norm_layer is None: | |
| norm_layer = nn.BatchNorm2d | |
| if groups != 1 or base_width != 64: | |
| raise ValueError('BasicBlock only supports groups=1 and base_width=64') | |
| if dilation > 1: | |
| raise NotImplementedError("Dilation > 1 not supported in BasicBlock") | |
| # Both self.conv1 and self.downsample layers downsample the input when stride != 1 | |
| self.conv1 = conv3x3(inplanes, planes, stride) | |
| self.bn1 = norm_layer(planes) | |
| self.relu = nn.ReLU(inplace=True) | |
| self.conv2 = conv3x3(planes, planes) | |
| self.bn2 = norm_layer(planes) | |
| self.downsample = downsample | |
| self.stride = stride | |
| def forward(self, x): | |
| identity = x | |
| out = self.conv1(x) | |
| out = self.bn1(out) | |
| out = self.relu(out) | |
| out = self.conv2(out) | |
| out = self.bn2(out) | |
| if self.downsample is not None: | |
| identity = self.downsample(x) | |
| out += identity | |
| out = self.relu(out) | |
| return out | |
| class Bottleneck(nn.Module): | |
| expansion = 4 | |
| def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1, | |
| base_width=64, dilation=1, norm_layer=None): | |
| super(Bottleneck, self).__init__() | |
| if norm_layer is None: | |
| norm_layer = nn.BatchNorm2d | |
| width = int(planes * (base_width / 64.)) * groups | |
| # Both self.conv2 and self.downsample layers downsample the input when stride != 1 | |
| self.conv1 = conv1x1(inplanes, width) | |
| self.bn1 = norm_layer(width) | |
| self.conv2 = conv3x3(width, width, stride, groups, dilation) | |
| self.bn2 = norm_layer(width) | |
| self.conv3 = conv1x1(width, planes * self.expansion) | |
| self.bn3 = norm_layer(planes * self.expansion) | |
| self.relu = nn.ReLU(inplace=True) | |
| self.downsample = downsample | |
| self.stride = stride | |
| def forward(self, x): | |
| identity = x | |
| out = self.conv1(x) | |
| out = self.bn1(out) | |
| out = self.relu(out) | |
| out = self.conv2(out) | |
| out = self.bn2(out) | |
| out = self.relu(out) | |
| out = self.conv3(out) | |
| out = self.bn3(out) | |
| if self.downsample is not None: | |
| identity = self.downsample(x) | |
| out += identity | |
| out = self.relu(out) | |
| return out | |
| class ResNet(nn.Module): | |
| def __init__(self, n_frames, block, layers, num_classes=1000, zero_init_residual=False, | |
| groups=1, width_per_group=64, replace_stride_with_dilation=None, | |
| norm_layer=None): | |
| super(ResNet, self).__init__() | |
| if norm_layer is None: | |
| norm_layer = nn.BatchNorm2d | |
| self._norm_layer = norm_layer | |
| self.inplanes = 64 | |
| self.dilation = 1 | |
| if replace_stride_with_dilation is None: | |
| # each element in the tuple indicates if we should replace | |
| # the 2x2 stride with a dilated convolution instead | |
| replace_stride_with_dilation = [False, False, False] | |
| if len(replace_stride_with_dilation) != 3: | |
| raise ValueError("replace_stride_with_dilation should be None " | |
| "or a 3-element tuple, got {}".format(replace_stride_with_dilation)) | |
| self.groups = groups | |
| self.base_width = width_per_group | |
| self.conv1 = nn.Conv2d(n_frames, self.inplanes, kernel_size=7, stride=2, padding=3, | |
| bias=False) | |
| self.bn1 = norm_layer(self.inplanes) | |
| self.relu = nn.ReLU(inplace=True) | |
| self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) | |
| # the actual output channels are 256 | |
| self.layer1 = self._make_layer(block, 64, layers[0]) | |
| self.layer2 = self._make_layer(block, 128, layers[1], stride=2, | |
| dilate=replace_stride_with_dilation[0]) | |
| self.layer3 = self._make_layer(block, 256, layers[2], stride=2, | |
| dilate=replace_stride_with_dilation[1]) | |
| self.layer4 = self._make_layer(block, 512, layers[3], stride=2, | |
| dilate=replace_stride_with_dilation[2]) | |
| self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) | |
| self.fc = nn.Linear(512 * block.expansion, num_classes) | |
| for m in self.modules(): | |
| if isinstance(m, nn.Conv2d): | |
| nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') | |
| elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)): | |
| nn.init.constant_(m.weight, 1) | |
| nn.init.constant_(m.bias, 0) | |
| # Zero-initialize the last BN in each residual branch, | |
| # so that the residual branch starts with zeros, and each residual block behaves like an identity. | |
| # This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677 | |
| if zero_init_residual: | |
| for m in self.modules(): | |
| if isinstance(m, Bottleneck): | |
| nn.init.constant_(m.bn3.weight, 0) | |
| elif isinstance(m, BasicBlock): | |
| nn.init.constant_(m.bn2.weight, 0) | |
| def _make_layer(self, block, planes, blocks, stride=1, dilate=False): | |
| norm_layer = self._norm_layer | |
| downsample = None | |
| previous_dilation = self.dilation | |
| if dilate: | |
| # dilation rate equals to the stride product of previous layers | |
| self.dilation *= stride | |
| stride = 1 | |
| if stride != 1 or self.inplanes != planes * block.expansion: | |
| downsample = nn.Sequential( | |
| conv1x1(self.inplanes, planes * block.expansion, stride), | |
| norm_layer(planes * block.expansion), | |
| ) | |
| layers = [] | |
| # Q: the dilation rate of the first layer remains the same with as the privious block? | |
| layers.append(block(self.inplanes, planes, stride, downsample, self.groups, | |
| self.base_width, previous_dilation, norm_layer)) | |
| self.inplanes = planes * block.expansion | |
| for _ in range(1, blocks): | |
| layers.append(block(self.inplanes, planes, groups=self.groups, | |
| base_width=self.base_width, dilation=self.dilation, | |
| norm_layer=norm_layer)) | |
| return nn.Sequential(*layers) | |
| 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 = self.layer3(x) | |
| x = self.layer4(x) | |
| x = self.avgpool(x) | |
| x = torch.flatten(x, 1) | |
| x = self.fc(x) | |
| return x | |
| def _resnet(arch, n_frames, block, layers, pretrained, progress, **kwargs): | |
| model = ResNet(n_frames, block, layers, **kwargs) | |
| return model | |
| def resnet101(n_frames, pretrained=False, progress=True, **kwargs): | |
| r"""ResNet-101 model from | |
| `"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_ | |
| Args: | |
| pretrained (bool): If True, returns a model pre-trained on ImageNet | |
| progress (bool): If True, displays a progress bar of the download to stderr | |
| """ | |
| return _resnet('resnet101', n_frames, Bottleneck, [3, 4, 23, 3], pretrained, progress, | |
| **kwargs) | |
| def _segm_resnet(name, backbone_name, num_classes, n_frames, output_stride, pretrained_backbone): | |
| if output_stride==8: | |
| replace_stride_with_dilation=[False, True, True] | |
| aspp_dilate = [12, 24, 36] | |
| else: | |
| replace_stride_with_dilation=[False, False, True] | |
| aspp_dilate = [6, 12, 18] | |
| backbone = resnet101(n_frames, pretrained=pretrained_backbone, | |
| replace_stride_with_dilation=replace_stride_with_dilation) | |
| inplanes = 2048 | |
| low_level_planes = 256 | |
| return_layers = {'layer4': 'out', 'layer1': 'low_level'} | |
| classifier = DeepLabHeadV3Plus(inplanes, low_level_planes, num_classes, aspp_dilate) | |
| backbone = IntermediateLayerGetter(backbone, return_layers=return_layers) | |
| model = DeepLabV3(backbone, classifier) | |
| return model | |
| def DeepLabV3Plus_Res101(n_classes=21, n_frames=5, output_stride=8, pretrained_backbone=False): | |
| """Constructs a DeepLabV3+ model with a ResNet-101 backbone. | |
| Args: | |
| num_classes (int): number of classes. | |
| output_stride (int): output stride for deeplab. | |
| pretrained_backbone (bool): If True, use the pretrained backbone. | |
| """ | |
| return _segm_resnet('deeplabv3plus', 'resnet101', n_classes, n_frames, output_stride=output_stride, pretrained_backbone=pretrained_backbone) |