CoolFace
Apppublic

leuschnm/CrowdCounting-with-Scale-Adaptive-Selection-SASNet

sourceHugging Facemitupdated 2y agoView on Hugging Face
11likes
model.py258 linesDownload Raw Back to root
1# Copyright 2021 Tencent2 3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6 7#     http://www.apache.org/licenses/LICENSE-2.08 9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14# =============================================================================15import torch16import torch.nn as nn17import torch.nn.functional as F18from torchvision import models19 20class Conv2d(nn.Module):21    def __init__(self, in_channels, out_channels, kernel_size, \22                stride=1, NL='relu', same_padding=False, bn=False, dilation=1):23        super(Conv2d, self).__init__()24        padding = int((kernel_size - 1) // 2) if same_padding else 025        self.conv = []26        if dilation==1:27            self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding=padding, dilation=dilation)28        else:29            self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding=dilation, dilation=dilation)30        self.bn = nn.BatchNorm2d(out_channels, eps=0.001, momentum=0, affine=True) if bn else nn.Identity()31        if NL == 'relu' :32            self.relu = nn.ReLU(inplace=True)33        elif NL == 'prelu':34            self.relu = nn.PReLU()35        else:36            self.relu = None37 38    def forward(self, x):39        x = self.conv(x)40        if self.bn is not None:41            x = self.bn(x)42        if self.relu is not None:43            x = self.relu(x)44        return x45 46# the main implementation of the SASNet47class SASNet(nn.Module):48    def __init__(self, pretrained=False, args=None):49        super(SASNet, self).__init__()50        # define the backbone network51        vgg = models.vgg16_bn(pretrained=pretrained)52 53        features = list(vgg.features.children())54        # get each stage of the backbone55        self.features1 = nn.Sequential(*features[0:6])56        self.features2 = nn.Sequential(*features[6:13])57        self.features3 = nn.Sequential(*features[13:23])58        self.features4 = nn.Sequential(*features[23:33])59        self.features5 = nn.Sequential(*features[33:43])60        # docoder definition61        self.de_pred5 = nn.Sequential(62            Conv2d(512, 1024, 3, same_padding=True, NL='relu'),63            Conv2d(1024, 512, 3, same_padding=True, NL='relu'),64        )65 66        self.de_pred4 = nn.Sequential(67            Conv2d(512 + 512, 512, 3, same_padding=True, NL='relu'),68            Conv2d(512, 256, 3, same_padding=True, NL='relu'),69        )70 71        self.de_pred3 = nn.Sequential(72            Conv2d(256 + 256, 256, 3, same_padding=True, NL='relu'),73            Conv2d(256, 128, 3, same_padding=True, NL='relu'),74        )75 76        self.de_pred2 = nn.Sequential(77            Conv2d(128 + 128, 128, 3, same_padding=True, NL='relu'),78            Conv2d(128, 64, 3, same_padding=True, NL='relu'),79        )80 81        self.de_pred1 = nn.Sequential(82            Conv2d(64 + 64, 64, 3, same_padding=True, NL='relu'),83            Conv2d(64, 64, 3, same_padding=True, NL='relu'),84        )85        # density head definition86        self.density_head5 = nn.Sequential(87            MultiBranchModule(512),88            Conv2d(2048, 1, 1, same_padding=True)89        )90 91        self.density_head4 = nn.Sequential(92            MultiBranchModule(256),93            Conv2d(1024, 1, 1, same_padding=True)94        )95 96        self.density_head3 = nn.Sequential(97            MultiBranchModule(128),98            Conv2d(512, 1, 1, same_padding=True)99        )100 101        self.density_head2 = nn.Sequential(102            MultiBranchModule(64),103            Conv2d(256, 1, 1, same_padding=True)104        )105 106        self.density_head1 = nn.Sequential(107            MultiBranchModule(64),108            Conv2d(256, 1, 1, same_padding=True)109        )110        # confidence head definition111        self.confidence_head5 = nn.Sequential(112            Conv2d(512, 256, 1, same_padding=True, NL='relu'),113            Conv2d(256, 1, 1, same_padding=True, NL=None)114        )115 116        self.confidence_head4 = nn.Sequential(117            Conv2d(256, 128, 1, same_padding=True, NL='relu'),118            Conv2d(128, 1, 1, same_padding=True, NL=None)119        )120 121        self.confidence_head3 = nn.Sequential(122            Conv2d(128, 64, 1, same_padding=True, NL='relu'),123            Conv2d(64, 1, 1, same_padding=True, NL=None)124        )125 126        self.confidence_head2 = nn.Sequential(127            Conv2d(64, 32, 1, same_padding=True, NL='relu'),128            Conv2d(32, 1, 1, same_padding=True, NL=None)129        )130 131        self.confidence_head1 = nn.Sequential(132            Conv2d(64, 32, 1, same_padding=True, NL='relu'),133            Conv2d(32, 1, 1, same_padding=True, NL=None)134        )135 136        self.block_size = 32137    # the forward process138    def forward(self, x):139        size = x.size()140        x1 = self.features1(x)141        x2 = self.features2(x1)142        x3 = self.features3(x2)143        x4 = self.features4(x3)144        x5 = self.features5(x4)145        # begining of decoding146        x = self.de_pred5(x5)147        x5_out = x148        x = F.upsample_bilinear(x, size=x4.size()[2:])149 150        x = torch.cat([x4, x], 1)151        x = self.de_pred4(x)152        x4_out = x153        x = F.upsample_bilinear(x, size=x3.size()[2:])154 155        x = torch.cat([x3, x], 1)156        x = self.de_pred3(x)157        x3_out = x158        x = F.upsample_bilinear(x, size=x2.size()[2:])159 160        x = torch.cat([x2, x], 1)161        x = self.de_pred2(x)162        x2_out = x163        x = F.upsample_bilinear(x, size=x1.size()[2:])164 165        x = torch.cat([x1, x], 1)166        x = self.de_pred1(x)167        x1_out = x168        # density prediction169        x5_density = self.density_head5(x5_out)170        x4_density = self.density_head4(x4_out)171        x3_density = self.density_head3(x3_out)172        x2_density = self.density_head2(x2_out)173        x1_density = self.density_head1(x1_out)174        # get patch features for confidence prediction175        x5_confi = F.adaptive_avg_pool2d(x5_out, output_size=(size[-2] // self.block_size, size[-1] // self.block_size))176        x4_confi = F.adaptive_avg_pool2d(x4_out, output_size=(size[-2] // self.block_size, size[-1] // self.block_size))177        x3_confi = F.adaptive_avg_pool2d(x3_out, output_size=(size[-2] // self.block_size, size[-1] // self.block_size))178        x2_confi = F.adaptive_avg_pool2d(x2_out, output_size=(size[-2] // self.block_size, size[-1] // self.block_size))179        x1_confi = F.adaptive_avg_pool2d(x1_out, output_size=(size[-2] // self.block_size, size[-1] // self.block_size))180        # confidence prediction181        x5_confi = self.confidence_head5(x5_confi)182        x4_confi = self.confidence_head4(x4_confi)183        x3_confi = self.confidence_head3(x3_confi)184        x2_confi = self.confidence_head2(x2_confi)185        x1_confi = self.confidence_head1(x1_confi)186        # upsample the density prediction to be the same with the input size187        x5_density = F.upsample_nearest(x5_density, size=x1.size()[2:])188        x4_density = F.upsample_nearest(x4_density, size=x1.size()[2:])189        x3_density = F.upsample_nearest(x3_density, size=x1.size()[2:])190        x2_density = F.upsample_nearest(x2_density, size=x1.size()[2:])191        x1_density = F.upsample_nearest(x1_density, size=x1.size()[2:])192        # upsample the confidence prediction to be the same with the input size193        x5_confi_upsample = F.upsample_nearest(x5_confi, size=x1.size()[2:])194        x4_confi_upsample = F.upsample_nearest(x4_confi, size=x1.size()[2:])195        x3_confi_upsample = F.upsample_nearest(x3_confi, size=x1.size()[2:])196        x2_confi_upsample = F.upsample_nearest(x2_confi, size=x1.size()[2:])197        x1_confi_upsample = F.upsample_nearest(x1_confi, size=x1.size()[2:])198 199        # =============================================================================================================200        # soft √201        confidence_map = torch.cat([x5_confi_upsample, x4_confi_upsample,202                                    x3_confi_upsample, x2_confi_upsample, x1_confi_upsample], 1)203        confidence_map = torch.nn.functional.sigmoid(confidence_map)204 205        # use softmax to normalize206        confidence_map = torch.nn.functional.softmax(confidence_map, 1)207 208        density_map = torch.cat([x5_density, x4_density, x3_density, x2_density, x1_density], 1)209        # soft selection210        density_map *= confidence_map211        density = torch.sum(density_map, 1, keepdim=True)212 213        return density214 215# the module definition for the multi-branch in the density head216class MultiBranchModule(nn.Module):217    def __init__(self, in_channels, sync=False):218        super(MultiBranchModule, self).__init__()219        self.branch1x1 = BasicConv2d(in_channels, in_channels//2, kernel_size=1, sync=sync)220        self.branch1x1_1 = BasicConv2d(in_channels//2, in_channels, kernel_size=1, sync=sync)221 222        self.branch3x3_1 = BasicConv2d(in_channels, in_channels//2, kernel_size=1, sync=sync)223        self.branch3x3_2 = BasicConv2d(in_channels // 2, in_channels, kernel_size=(3, 3), padding=(1, 1), sync=sync)224 225        self.branch3x3dbl_1 = BasicConv2d(in_channels, in_channels//2, kernel_size=1, sync=sync)226        self.branch3x3dbl_2 = BasicConv2d(in_channels // 2, in_channels, kernel_size=5, padding=2, sync=sync)227 228    def forward(self, x):229        branch1x1 = self.branch1x1(x)230        branch1x1 = self.branch1x1_1(branch1x1)231 232        branch3x3 = self.branch3x3_1(x)233        branch3x3 = self.branch3x3_2(branch3x3)234 235        branch3x3dbl = self.branch3x3dbl_1(x)236        branch3x3dbl = self.branch3x3dbl_2(branch3x3dbl)237 238        outputs = [branch1x1, branch3x3, branch3x3dbl, x]239        return torch.cat(outputs, 1)240 241# the module definition for the basic conv module242class BasicConv2d(nn.Module):243 244    def __init__(self, in_channels, out_channels, sync=False, **kwargs):245        super(BasicConv2d, self).__init__()246        self.conv = nn.Conv2d(in_channels, out_channels, bias=False, **kwargs)247        if sync:248            # for sync bn249            print('use sync inception')250            self.bn = nn.SyncBatchNorm(out_channels, eps=0.001)251        else:252            self.bn = nn.BatchNorm2d(out_channels, eps=0.001)253 254    def forward(self, x):255        x = self.conv(x)256        x = self.bn(x)257        return F.relu(x, inplace=True)258