//  [python]
def forward(self, x):
        size = x.size()
        x1 = self.features1(x)
        x2 = self.features2(x1)
        x3 = self.features3(x2)
        x4 = self.features4(x3)
        x5 = self.features5(x4)
        # begining of decoding
        x = self.de_pred5(x5)
        x5_out = x
        x = F.interpolate(x, size=x4.size()[2:], mode='bilinear')

        x = torch.cat([x4, x], 1)
        x = self.de_pred4(x)
        x4_out = x
        x = F.interpolate(x, size=x3.size()[2:], mode='bilinear')

        x = torch.cat([x3, x], 1)
        x = self.de_pred3(x)
        x3_out = x
        x = F.interpolate(x, size=x2.size()[2:], mode='bilinear')

        x = torch.cat([x2, x], 1)
        x = self.de_pred2(x)
        x2_out = x
        x = F.interpolate(x, size=x1.size()[2:], mode='bilinear')

        x = torch.cat([x1, x], 1)
        x = self.de_pred1(x)
        x1_out = x
        # density prediction
        x5_density = self.density_head5(x5_out)
        x4_density = self.density_head4(x4_out)
        x3_density = self.density_head3(x3_out)
        x2_density = self.density_head2(x2_out)
        x1_density = self.density_head1(x1_out)
        # get patch features for confidence prediction
        x5_confi = F.adaptive_avg_pool2d(x5_out, output_size=(size[-2] // self.block_size, size[-1] // self.block_size))
        x4_confi = F.adaptive_avg_pool2d(x4_out, output_size=(size[-2] // self.block_size, size[-1] // self.block_size))
        x3_confi = F.adaptive_avg_pool2d(x3_out, output_size=(size[-2] // self.block_size, size[-1] // self.block_size))
        x2_confi = F.adaptive_avg_pool2d(x2_out, output_size=(size[-2] // self.block_size, size[-1] // self.block_size))
        x1_confi = F.adaptive_avg_pool2d(x1_out, output_size=(size[-2] // self.block_size, size[-1] // self.block_size))
        # confidence prediction
        x5_confi = self.confidence_head5(x5_confi)
        x4_confi = self.confidence_head4(x4_confi)
        x3_confi = self.confidence_head3(x3_confi)
        x2_confi = self.confidence_head2(x2_confi)
        x1_confi = self.confidence_head1(x1_confi)
        # upsample the density prediction to be the same with the input size
        x5_density = F.interpolate(x5_density, size=x1.size()[2:], mode='nearest')
        x4_density = F.interpolate(x4_density, size=x1.size()[2:], mode='nearest')
        x3_density = F.interpolate(x3_density, size=x1.size()[2:], mode='nearest')
        x2_density = F.interpolate(x2_density, size=x1.size()[2:], mode='nearest')
        x1_density = F.interpolate(x1_density, size=x1.size()[2:], mode='nearest')
        # upsample the confidence prediction to be the same with the input size
        x5_confi_upsample = F.interpolate(x5_confi, size=x1.size()[2:], mode='nearest')
        x4_confi_upsample = F.interpolate(x4_confi, size=x1.size()[2:], mode='nearest')
        x3_confi_upsample = F.interpolate(x3_confi, size=x1.size()[2:], mode='nearest')
        x2_confi_upsample = F.interpolate(x2_confi, size=x1.size()[2:], mode='nearest')
        x1_confi_upsample = F.interpolate(x1_confi, size=x1.size()[2:], mode='nearest')

        # =============================================================================================================
        # soft √
        confidence_map = torch.cat([x5_confi_upsample, x4_confi_upsample,
                                    x3_confi_upsample, x2_confi_upsample, x1_confi_upsample], 1)
        confidence_map = torch.nn.functional.sigmoid(confidence_map)

        # use softmax to normalize
        confidence_map = torch.nn.functional.softmax(confidence_map, 1)

        density_map = torch.cat([x5_density, x4_density, x3_density, x2_density, x1_density], 1)
        # soft selection
        density_map *= confidence_map
        density = torch.sum(density_map, 1, keepdim=True)

        return density