class_docstr: Module, which estimates the second moment matrix of the patch gradients.
  
  The method determines the affine shape of the local feature as in :cite:`baumberg2000`.
  
  Args:
      patch_size: the input image patch size.
      eps: for safe division.
docstr: Args:
      patch: :math:`(B, 1, H, W)`
  
  Returns:
      torch.Tensor: ellipse_shape :math:`(B, 1, 3)`
docstr_tok: ["Args",":","patch",":",":","math",":","`","(","B",",","1",",","H",",","W",")","`","Returns",":","torch.Tensor",":","ellipse_shape",":","math",":","`","(","B",",","1",",","3",")","`"]
code: def forward(self, patch: torch.Tensor) -> torch.Tensor:
      """
      Args:
          patch: :math:`(B, 1, H, W)`
  
      Returns:
          torch.Tensor: ellipse_shape :math:`(B, 1, 3)`
  
      """
      KORNIA_CHECK_SHAPE(patch, ["B", "1", "H", "W"])
      self.weighting = self.weighting.to(patch.dtype).to(patch.device)
      grads: torch.Tensor = self.gradient(patch) * self.weighting
      # unpack the edges
      gx: torch.Tensor = grads[:, :, 0]
      gy: torch.Tensor = grads[:, :, 1]
      # abc == 1st axis, mixture, 2nd axis. Ellipse_shape is a 2nd moment matrix.
      ellipse_shape = torch.cat(
          [
              gx.pow(2).mean(dim=2).mean(dim=2, keepdim=True),
              (gx * gy).mean(dim=2).mean(dim=2, keepdim=True),
              gy.pow(2).mean(dim=2).mean(dim=2, keepdim=True),
          ],
          dim=2,
      )
  
      # Now lets detect degenerate cases: when 2 or 3 elements are close to zero (e.g. if patch is completely black
      bad_mask = (
          (ellipse_shape < self.eps).float().sum(dim=2, keepdim=True)
          >= 2
      ).to(ellipse_shape.dtype)
      # We will replace degenerate shape with circular shapes.
      circular_shape = (
          torch.tensor([1.0, 0.0, 1.0])
          .to(ellipse_shape.device)
          .to(ellipse_shape.dtype)
          .view(1, 1, 3)
      )
      ellipse_shape = (
          ellipse_shape * (1.0 - bad_mask) + circular_shape * bad_mask
      )
      # normalization
      ellipse_shape = (
          ellipse_shape / ellipse_shape.max(dim=2, keepdim=True)[0]
      )
      return ellipse_shape
  
imports: import math
  import warnings
  from typing import Dict, Optional
  import torch
  from torch import nn
  from kornia.core.check import KORNIA_CHECK_LAF, KORNIA_CHECK_SHAPE
  from kornia.filters.kernels import get_gaussian_kernel2d
  from kornia.filters.sobel import SpatialGradient
  from kornia.utils.helpers import map_location_to_cpu
  from .laf import ellipse_to_laf, extract_patches_from_pyramid, get_laf_orientation, get_laf_scale, make_upright, scale_laf, set_laf_orientation
label_desc: Use image node_id 3 for calling the PatchAffineShapeEstimator obj's underlying member method code with example usage: obj.forward(patch) and returns: ellipse_shape