Team Ai
Apppublic

Arulkumar03/Fox_Sheep_Detector_Computer_Vision_model

sourceHugging Facemitupdated 3y agoView on Hugging Face
0likes
deform_conv.py515 linesDownload Raw Back to layers
1# Copyright (c) Facebook, Inc. and its affiliates.2import math3from functools import lru_cache4import torch5from torch import nn6from torch.autograd import Function7from torch.autograd.function import once_differentiable8from torch.nn.modules.utils import _pair9from torchvision.ops import deform_conv2d10 11from detectron2.utils.develop import create_dummy_class, create_dummy_func12 13from .wrappers import _NewEmptyTensorOp14 15 16class _DeformConv(Function):17    @staticmethod18    def forward(19        ctx,20        input,21        offset,22        weight,23        stride=1,24        padding=0,25        dilation=1,26        groups=1,27        deformable_groups=1,28        im2col_step=64,29    ):30        if input is not None and input.dim() != 4:31            raise ValueError(32                "Expected 4D tensor as input, got {}D tensor instead.".format(input.dim())33            )34        ctx.stride = _pair(stride)35        ctx.padding = _pair(padding)36        ctx.dilation = _pair(dilation)37        ctx.groups = groups38        ctx.deformable_groups = deformable_groups39        ctx.im2col_step = im2col_step40 41        ctx.save_for_backward(input, offset, weight)42 43        output = input.new_empty(44            _DeformConv._output_size(input, weight, ctx.padding, ctx.dilation, ctx.stride)45        )46 47        ctx.bufs_ = [input.new_empty(0), input.new_empty(0)]  # columns, ones48 49        if not input.is_cuda:50            # TODO: let torchvision support full features of our deformconv.51            if deformable_groups != 1:52                raise NotImplementedError(53                    "Deformable Conv with deformable_groups != 1 is not supported on CPUs!"54                )55            return deform_conv2d(56                input, offset, weight, stride=stride, padding=padding, dilation=dilation57            )58        else:59            cur_im2col_step = _DeformConv._cal_im2col_step(input.shape[0], ctx.im2col_step)60            assert (input.shape[0] % cur_im2col_step) == 0, "im2col step must divide batchsize"61 62            _C.deform_conv_forward(63                input,64                weight,65                offset,66                output,67                ctx.bufs_[0],68                ctx.bufs_[1],69                weight.size(3),70                weight.size(2),71                ctx.stride[1],72                ctx.stride[0],73                ctx.padding[1],74                ctx.padding[0],75                ctx.dilation[1],76                ctx.dilation[0],77                ctx.groups,78                ctx.deformable_groups,79                cur_im2col_step,80            )81        return output82 83    @staticmethod84    @once_differentiable85    def backward(ctx, grad_output):86        input, offset, weight = ctx.saved_tensors87 88        grad_input = grad_offset = grad_weight = None89 90        if not grad_output.is_cuda:91            raise NotImplementedError("Deformable Conv is not supported on CPUs!")92        else:93            cur_im2col_step = _DeformConv._cal_im2col_step(input.shape[0], ctx.im2col_step)94            assert (input.shape[0] % cur_im2col_step) == 0, "im2col step must divide batchsize"95 96            if ctx.needs_input_grad[0] or ctx.needs_input_grad[1]:97                grad_input = torch.zeros_like(input)98                grad_offset = torch.zeros_like(offset)99                _C.deform_conv_backward_input(100                    input,101                    offset,102                    grad_output,103                    grad_input,104                    grad_offset,105                    weight,106                    ctx.bufs_[0],107                    weight.size(3),108                    weight.size(2),109                    ctx.stride[1],110                    ctx.stride[0],111                    ctx.padding[1],112                    ctx.padding[0],113                    ctx.dilation[1],114                    ctx.dilation[0],115                    ctx.groups,116                    ctx.deformable_groups,117                    cur_im2col_step,118                )119 120            if ctx.needs_input_grad[2]:121                grad_weight = torch.zeros_like(weight)122                _C.deform_conv_backward_filter(123                    input,124                    offset,125                    grad_output,126                    grad_weight,127                    ctx.bufs_[0],128                    ctx.bufs_[1],129                    weight.size(3),130                    weight.size(2),131                    ctx.stride[1],132                    ctx.stride[0],133                    ctx.padding[1],134                    ctx.padding[0],135                    ctx.dilation[1],136                    ctx.dilation[0],137                    ctx.groups,138                    ctx.deformable_groups,139                    1,140                    cur_im2col_step,141                )142 143        return grad_input, grad_offset, grad_weight, None, None, None, None, None, None144 145    @staticmethod146    def _output_size(input, weight, padding, dilation, stride):147        channels = weight.size(0)148        output_size = (input.size(0), channels)149        for d in range(input.dim() - 2):150            in_size = input.size(d + 2)151            pad = padding[d]152            kernel = dilation[d] * (weight.size(d + 2) - 1) + 1153            stride_ = stride[d]154            output_size += ((in_size + (2 * pad) - kernel) // stride_ + 1,)155        if not all(map(lambda s: s > 0, output_size)):156            raise ValueError(157                "convolution input is too small (output would be {})".format(158                    "x".join(map(str, output_size))159                )160            )161        return output_size162 163    @staticmethod164    @lru_cache(maxsize=128)165    def _cal_im2col_step(input_size, default_size):166        """167        Calculate proper im2col step size, which should be divisible by input_size and not larger168        than prefer_size. Meanwhile the step size should be as large as possible to be more169        efficient. So we choose the largest one among all divisors of input_size which are smaller170        than prefer_size.171        :param input_size: input batch size .172        :param default_size: default preferred im2col step size.173        :return: the largest proper step size.174        """175        if input_size <= default_size:176            return input_size177        best_step = 1178        for step in range(2, min(int(math.sqrt(input_size)) + 1, default_size)):179            if input_size % step == 0:180                if input_size // step <= default_size:181                    return input_size // step182                best_step = step183 184        return best_step185 186 187class _ModulatedDeformConv(Function):188    @staticmethod189    def forward(190        ctx,191        input,192        offset,193        mask,194        weight,195        bias=None,196        stride=1,197        padding=0,198        dilation=1,199        groups=1,200        deformable_groups=1,201    ):202        ctx.stride = stride203        ctx.padding = padding204        ctx.dilation = dilation205        ctx.groups = groups206        ctx.deformable_groups = deformable_groups207        ctx.with_bias = bias is not None208        if not ctx.with_bias:209            bias = input.new_empty(1)  # fake tensor210        if not input.is_cuda:211            raise NotImplementedError("Deformable Conv is not supported on CPUs!")212        if (213            weight.requires_grad214            or mask.requires_grad215            or offset.requires_grad216            or input.requires_grad217        ):218            ctx.save_for_backward(input, offset, mask, weight, bias)219        output = input.new_empty(_ModulatedDeformConv._infer_shape(ctx, input, weight))220        ctx._bufs = [input.new_empty(0), input.new_empty(0)]221        _C.modulated_deform_conv_forward(222            input,223            weight,224            bias,225            ctx._bufs[0],226            offset,227            mask,228            output,229            ctx._bufs[1],230            weight.shape[2],231            weight.shape[3],232            ctx.stride,233            ctx.stride,234            ctx.padding,235            ctx.padding,236            ctx.dilation,237            ctx.dilation,238            ctx.groups,239            ctx.deformable_groups,240            ctx.with_bias,241        )242        return output243 244    @staticmethod245    @once_differentiable246    def backward(ctx, grad_output):247        if not grad_output.is_cuda:248            raise NotImplementedError("Deformable Conv is not supported on CPUs!")249        input, offset, mask, weight, bias = ctx.saved_tensors250        grad_input = torch.zeros_like(input)251        grad_offset = torch.zeros_like(offset)252        grad_mask = torch.zeros_like(mask)253        grad_weight = torch.zeros_like(weight)254        grad_bias = torch.zeros_like(bias)255        _C.modulated_deform_conv_backward(256            input,257            weight,258            bias,259            ctx._bufs[0],260            offset,261            mask,262            ctx._bufs[1],263            grad_input,264            grad_weight,265            grad_bias,266            grad_offset,267            grad_mask,268            grad_output,269            weight.shape[2],270            weight.shape[3],271            ctx.stride,272            ctx.stride,273            ctx.padding,274            ctx.padding,275            ctx.dilation,276            ctx.dilation,277            ctx.groups,278            ctx.deformable_groups,279            ctx.with_bias,280        )281        if not ctx.with_bias:282            grad_bias = None283 284        return (285            grad_input,286            grad_offset,287            grad_mask,288            grad_weight,289            grad_bias,290            None,291            None,292            None,293            None,294            None,295        )296 297    @staticmethod298    def _infer_shape(ctx, input, weight):299        n = input.size(0)300        channels_out = weight.size(0)301        height, width = input.shape[2:4]302        kernel_h, kernel_w = weight.shape[2:4]303        height_out = (304            height + 2 * ctx.padding - (ctx.dilation * (kernel_h - 1) + 1)305        ) // ctx.stride + 1306        width_out = (307            width + 2 * ctx.padding - (ctx.dilation * (kernel_w - 1) + 1)308        ) // ctx.stride + 1309        return n, channels_out, height_out, width_out310 311 312deform_conv = _DeformConv.apply313modulated_deform_conv = _ModulatedDeformConv.apply314 315 316class DeformConv(nn.Module):317    def __init__(318        self,319        in_channels,320        out_channels,321        kernel_size,322        stride=1,323        padding=0,324        dilation=1,325        groups=1,326        deformable_groups=1,327        bias=False,328        norm=None,329        activation=None,330    ):331        """332        Deformable convolution from :paper:`deformconv`.333 334        Arguments are similar to :class:`Conv2D`. Extra arguments:335 336        Args:337            deformable_groups (int): number of groups used in deformable convolution.338            norm (nn.Module, optional): a normalization layer339            activation (callable(Tensor) -> Tensor): a callable activation function340        """341        super(DeformConv, self).__init__()342 343        assert not bias344        assert in_channels % groups == 0, "in_channels {} cannot be divisible by groups {}".format(345            in_channels, groups346        )347        assert (348            out_channels % groups == 0349        ), "out_channels {} cannot be divisible by groups {}".format(out_channels, groups)350 351        self.in_channels = in_channels352        self.out_channels = out_channels353        self.kernel_size = _pair(kernel_size)354        self.stride = _pair(stride)355        self.padding = _pair(padding)356        self.dilation = _pair(dilation)357        self.groups = groups358        self.deformable_groups = deformable_groups359        self.norm = norm360        self.activation = activation361 362        self.weight = nn.Parameter(363            torch.Tensor(out_channels, in_channels // self.groups, *self.kernel_size)364        )365        self.bias = None366 367        nn.init.kaiming_uniform_(self.weight, nonlinearity="relu")368 369    def forward(self, x, offset):370        if x.numel() == 0:371            # When input is empty, we want to return a empty tensor with "correct" shape,372            # So that the following operations will not panic373            # if they check for the shape of the tensor.374            # This computes the height and width of the output tensor375            output_shape = [376                (i + 2 * p - (di * (k - 1) + 1)) // s + 1377                for i, p, di, k, s in zip(378                    x.shape[-2:], self.padding, self.dilation, self.kernel_size, self.stride379                )380            ]381            output_shape = [x.shape[0], self.weight.shape[0]] + output_shape382            return _NewEmptyTensorOp.apply(x, output_shape)383 384        x = deform_conv(385            x,386            offset,387            self.weight,388            self.stride,389            self.padding,390            self.dilation,391            self.groups,392            self.deformable_groups,393        )394        if self.norm is not None:395            x = self.norm(x)396        if self.activation is not None:397            x = self.activation(x)398        return x399 400    def extra_repr(self):401        tmpstr = "in_channels=" + str(self.in_channels)402        tmpstr += ", out_channels=" + str(self.out_channels)403        tmpstr += ", kernel_size=" + str(self.kernel_size)404        tmpstr += ", stride=" + str(self.stride)405        tmpstr += ", padding=" + str(self.padding)406        tmpstr += ", dilation=" + str(self.dilation)407        tmpstr += ", groups=" + str(self.groups)408        tmpstr += ", deformable_groups=" + str(self.deformable_groups)409        tmpstr += ", bias=False"410        return tmpstr411 412 413class ModulatedDeformConv(nn.Module):414    def __init__(415        self,416        in_channels,417        out_channels,418        kernel_size,419        stride=1,420        padding=0,421        dilation=1,422        groups=1,423        deformable_groups=1,424        bias=True,425        norm=None,426        activation=None,427    ):428        """429        Modulated deformable convolution from :paper:`deformconv2`.430 431        Arguments are similar to :class:`Conv2D`. Extra arguments:432 433        Args:434            deformable_groups (int): number of groups used in deformable convolution.435            norm (nn.Module, optional): a normalization layer436            activation (callable(Tensor) -> Tensor): a callable activation function437        """438        super(ModulatedDeformConv, self).__init__()439        self.in_channels = in_channels440        self.out_channels = out_channels441        self.kernel_size = _pair(kernel_size)442        self.stride = stride443        self.padding = padding444        self.dilation = dilation445        self.groups = groups446        self.deformable_groups = deformable_groups447        self.with_bias = bias448        self.norm = norm449        self.activation = activation450 451        self.weight = nn.Parameter(452            torch.Tensor(out_channels, in_channels // groups, *self.kernel_size)453        )454        if bias:455            self.bias = nn.Parameter(torch.Tensor(out_channels))456        else:457            self.bias = None458 459        nn.init.kaiming_uniform_(self.weight, nonlinearity="relu")460        if self.bias is not None:461            nn.init.constant_(self.bias, 0)462 463    def forward(self, x, offset, mask):464        if x.numel() == 0:465            output_shape = [466                (i + 2 * p - (di * (k - 1) + 1)) // s + 1467                for i, p, di, k, s in zip(468                    x.shape[-2:], self.padding, self.dilation, self.kernel_size, self.stride469                )470            ]471            output_shape = [x.shape[0], self.weight.shape[0]] + output_shape472            return _NewEmptyTensorOp.apply(x, output_shape)473 474        x = modulated_deform_conv(475            x,476            offset,477            mask,478            self.weight,479            self.bias,480            self.stride,481            self.padding,482            self.dilation,483            self.groups,484            self.deformable_groups,485        )486        if self.norm is not None:487            x = self.norm(x)488        if self.activation is not None:489            x = self.activation(x)490        return x491 492    def extra_repr(self):493        tmpstr = "in_channels=" + str(self.in_channels)494        tmpstr += ", out_channels=" + str(self.out_channels)495        tmpstr += ", kernel_size=" + str(self.kernel_size)496        tmpstr += ", stride=" + str(self.stride)497        tmpstr += ", padding=" + str(self.padding)498        tmpstr += ", dilation=" + str(self.dilation)499        tmpstr += ", groups=" + str(self.groups)500        tmpstr += ", deformable_groups=" + str(self.deformable_groups)501        tmpstr += ", bias=" + str(self.with_bias)502        return tmpstr503 504 505try:506    from detectron2 import _C507except ImportError:508    # TODO: register ops natively so there is no need to import _C.509    _msg = "detectron2 is not compiled successfully, please build following the instructions!"510    _args = ("detectron2._C", _msg)511    DeformConv = create_dummy_class("DeformConv", *_args)512    ModulatedDeformConv = create_dummy_class("ModulatedDeformConv", *_args)513    deform_conv = create_dummy_func("deform_conv", *_args)514    modulated_deform_conv = create_dummy_func("modulated_deform_conv", *_args)515