class_docstr: Module, which extracts patches using input images and local affine frames (LAFs).
  
  Then runs AffNet on patches to estimate LAFs shape. This is based on the original code from paper
  "Repeatability Is Not Enough: Learning Discriminative Affine Regions via Discriminability"".
  See :cite:`AffNet2018` for more details.
  
  Then original LAF shape is replaced with estimated one. The original LAF orientation is not preserved,
  so it is recommended to first run LAFAffineShapeEstimator and then LAFOrienter.
  
  Args:
      pretrained: Download and set pretrained weights to the model.
docstr: Args:
      LAF: :math:`(B, N, 2, 3)`
      img: :math:`(B, 1, H, W)`
  
  Returns:
      LAF_out: :math:`(B, N, 2, 3)`
docstr_tok: ["Args",":","LAF",":",":","math",":","`","(","B",",","N",",","2",",","3",")","`","img",":",":","math",":","`","(","B",",","1",",","H",",","W",")","`","Returns",":","LAF_out",":",":","math",":","`","(","B",",","N",",","2",",","3",")","`"]
code: def forward(
      self, laf: torch.Tensor, img: torch.Tensor
  ) -> torch.Tensor:
      """
      Args:
          LAF: :math:`(B, N, 2, 3)`
          img: :math:`(B, 1, H, W)`
  
      Returns:
          LAF_out: :math:`(B, N, 2, 3)`
      """
      KORNIA_CHECK_LAF(laf)
      KORNIA_CHECK_SHAPE(img, ["B", "1", "H", "W"])
      B, N = laf.shape[:2]
      PS: int = self.patch_size
      patches: torch.Tensor = extract_patches_from_pyramid(
          img, make_upright(laf), PS, True
      ).view(-1, 1, PS, PS)
      xy = self.features(self._normalize_input(patches)).view(-1, 3)
      a1 = torch.cat(
          [
              1.0 + xy[:, 0].reshape(-1, 1, 1),
              0 * xy[:, 0].reshape(-1, 1, 1),
          ],
          dim=2,
      )
      a2 = torch.cat(
          [
              xy[:, 1].reshape(-1, 1, 1),
              1.0 + xy[:, 2].reshape(-1, 1, 1),
          ],
          dim=2,
      )
      new_laf_no_center = torch.cat([a1, a2], dim=1).reshape(B, N, 2, 2)
      new_laf = torch.cat([new_laf_no_center, laf[:, :, :, 2:3]], dim=3)
      scale_orig = get_laf_scale(laf)
      if self.preserve_orientation:
          ori_orig = get_laf_orientation(laf)
      ellipse_scale = get_laf_scale(new_laf)
      laf_out = scale_laf(
          make_upright(new_laf), scale_orig / ellipse_scale
      )
      if self.preserve_orientation:
          laf_out = set_laf_orientation(laf_out, ori_orig)
      return laf_out
  
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 LAFAffNetShapeEstimator obj's underlying member method code with example usage: obj.forward(laf, img) and returns: laf_out