class_docstr: The class for implementing TextSnake loss. This is partially adapted
  from https://github.com/princewang1994/TextSnake.pytorch.
  
  TextSnake: `A Flexible Representation for Detecting Text of Arbitrary
  Shapes <https://arxiv.org/abs/1807.01544>`_.
  
  Args:
      ohem_ratio (float): The negative/positive ratio in ohem.
      downsample_ratio (float): Downsample ratio. Defaults to 1.0. TODO:
          remove it.
      orientation_thr (float): The threshold for distinguishing between
          head edge and tail edge among the horizontal and vertical edges
          of a quadrangle.
      resample_step (float): The step of resampling.
      center_region_shrink_ratio (float): The shrink ratio of text center.
      loss_text (dict): The loss config used to calculate the text loss.
      loss_center (dict): The loss config used to calculate the center loss.
      loss_radius (dict): The loss config used to calculate the radius loss.
      loss_sin (dict): The loss config used to calculate the sin loss.
      loss_cos (dict): The loss config used to calculate the cos loss.
docstr: Args:
      preds (Tensor): The prediction map of shape
          :math:`(N, 5, H, W)`, where each dimension is the map of
          "text_region", "center_region", "sin_map", "cos_map", and
          "radius_map" respectively.
      data_samples (list[TextDetDataSample]): The data samples.
  
  Returns:
      dict:  A loss dict with ``loss_text``, ``loss_center``,
      ``loss_radius``, ``loss_sin`` and ``loss_cos``.
docstr_tok: ["Args",":","preds","(","Tensor",")",":","The","prediction","map","of","shape",":","math",":","`","(","N",",","5",",","H",",","W",")","`",",","where","each","dimension","is","the","map","of","``","text_region","''",",","``","center_region","''",",","``","sin_map","''",",","``","cos_map","''",",","and","``","radius_map","''","respectively",".","data_samples","(","list","[","TextDetDataSample","]",")",":","The","data","samples",".","Returns",":","dict",":","A","loss","dict","with","``","loss_text","``",",","``","loss_center","``",",","``","loss_radius","``",",","``","loss_sin","``","and","``","loss_cos","``","."]
code: def forward(
      self, preds: Tensor, data_samples: Sequence[TextDetDataSample]
  ) -> Dict:
      """
      Args:
          preds (Tensor): The prediction map of shape
              :math:`(N, 5, H, W)`, where each dimension is the map of
              "text_region", "center_region", "sin_map", "cos_map", and
              "radius_map" respectively.
          data_samples (list[TextDetDataSample]): The data samples.
  
      Returns:
          dict:  A loss dict with ``loss_text``, ``loss_center``,
          ``loss_radius``, ``loss_sin`` and ``loss_cos``.
      """
  
      (
          gt_text_masks,
          gt_masks,
          gt_center_region_masks,
          gt_radius_maps,
          gt_sin_maps,
          gt_cos_maps,
      ) = self.get_targets(data_samples)
  
      pred_text_region = preds[:, 0, :, :]
      pred_center_region = preds[:, 1, :, :]
      pred_sin_map = preds[:, 2, :, :]
      pred_cos_map = preds[:, 3, :, :]
      pred_radius_map = preds[:, 4, :, :]
      feature_sz = preds.size()
      device = preds.device
  
      mapping = {
          "gt_text_masks": gt_text_masks,
          "gt_center_region_masks": gt_center_region_masks,
          "gt_masks": gt_masks,
          "gt_radius_maps": gt_radius_maps,
          "gt_sin_maps": gt_sin_maps,
          "gt_cos_maps": gt_cos_maps,
      }
      gt = {}
      for key, value in mapping.items():
          gt[key] = value
          if abs(self.downsample_ratio - 1.0) < 1e-2:
              gt[key] = self._batch_pad(gt[key], feature_sz[2:])
          else:
              gt[key] = [
                  imrescale(
                      mask,
                      scale=self.downsample_ratio,
                      interpolation="nearest",
                  )
                  for mask in gt[key]
              ]
              gt[key] = self._batch_pad(gt[key], feature_sz[2:])
              if key == "gt_radius_maps":
                  gt[key] *= self.downsample_ratio
          gt[key] = torch.from_numpy(gt[key]).float().to(device)
  
      scale = torch.sqrt(
          1.0 / (pred_sin_map**2 + pred_cos_map**2 + 1e-8)
      )
      pred_sin_map = pred_sin_map * scale
      pred_cos_map = pred_cos_map * scale
  
      loss_text = self.loss_text(
          pred_text_region, gt["gt_text_masks"], gt["gt_masks"]
      )
  
      text_mask = (gt["gt_text_masks"] * gt["gt_masks"]).float()
      loss_center = self.loss_center(
          pred_center_region, gt["gt_center_region_masks"], text_mask
      )
  
      center_mask = (
          gt["gt_center_region_masks"] * gt["gt_masks"]
      ).float()
      map_sz = pred_radius_map.size()
      ones = torch.ones(map_sz, dtype=torch.float, device=device)
      loss_radius = self.loss_radius(
          pred_radius_map / (gt["gt_radius_maps"] + 1e-2),
          ones,
          center_mask,
      )
      loss_sin = self.loss_sin(
          pred_sin_map, gt["gt_sin_maps"], center_mask
      )
      loss_cos = self.loss_cos(
          pred_cos_map, gt["gt_cos_maps"], center_mask
      )
  
      results = dict(
          loss_text=loss_text,
          loss_center=loss_center,
          loss_radius=loss_radius,
          loss_sin=loss_sin,
          loss_cos=loss_cos,
      )
  
      return results
  
imports: from typing import Dict, List, Sequence, Tuple
  import cv2
  import numpy
  import torch
  from mmcv.image import impad, imrescale
  from mmdet.models.utils import multi_apply
  from numpy import ndarray
  from numpy.linalg import norm
  from torch import Tensor
  from mmocr.registry import MODELS
  from mmocr.structures import TextDetDataSample
  from .seg_based_module_loss import SegBasedModuleLoss
label_desc: Use image node_id 3 for calling the TextSnakeModuleLoss obj's underlying member method code with example usage: obj.forward(preds, data_samples) and returns: results