class_docstr: Implement TPS transform.
  
  This was partially adapted from https://github.com/ayumiymk/aster.pytorch
  
  Args:
      output_image_size (tuple[int, int]): The size of the output image.
          Defaults to (32, 128).
      num_control_points (int): The number of control points. Defaults to 20.
      margins (tuple[float, float]): The margins for control points to the
          top and down side of the image. Defaults to [0.05, 0.05].
class_docstr_tok: ["Implement","TPS","transform",".","This","was","partially","adapted","from","https",":","\/\/github.com\/ayumiymk\/aster.pytorch","Args",":","output_image_size","(","tuple","[","int",",","int","]",")",":","The","size","of","the","output","image",".","Defaults","to","(","32",",","128",")",".","num_control_points","(","int",")",":","The","number","of","control","points",".","Defaults","to","20.","margins","(","tuple","[","float",",","float","]",")",":","The","margins","for","control","points","to","the","top","and","down","side","of","the","image",".","Defaults","to","[","0.05",",","0.05","]","."]
docstr: Forward function of the TPS block.
  
  Args:
      input (Tensor): The input image.
      source_control_points (Tensor): The control points of the source
          image of shape (N, self.num_control_points, 2).
  Returns:
      Tensor: The output image after TPS transform.
docstr_tok: ["Forward","function","of","the","TPS","block",".","Args",":","input","(","Tensor",")",":","The","input","image",".","source_control_points","(","Tensor",")",":","The","control","points","of","the","source","image","of","shape","(","N",",","self.num_control_points",",","2",")",".","Returns",":","Tensor",":","The","output","image","after","TPS","transform","."]
code: def forward(
      self, input: torch.Tensor, source_control_points: torch.Tensor
  ) -> torch.Tensor:
      """Forward function of the TPS block.
  
      Args:
          input (Tensor): The input image.
          source_control_points (Tensor): The control points of the source
              image of shape (N, self.num_control_points, 2).
      Returns:
          Tensor: The output image after TPS transform.
      """
      assert source_control_points.ndimension() == 3
      assert source_control_points.size(1) == self.num_control_points
      assert source_control_points.size(2) == 2
      batch_size = source_control_points.size(0)
  
      Y = torch.cat(
          [
              source_control_points,
              self.padding_matrix.expand(batch_size, 3, 2),
          ],
          1,
      )
      mapping_matrix = torch.matmul(self.inverse_kernel, Y)
      source_coordinate = torch.matmul(
          self.target_coordinate_repr, mapping_matrix
      )
  
      grid = source_coordinate.view(
          -1, self.target_height, self.target_width, 2
      )
      grid = torch.clamp(grid, 0, 1)
      grid = 2.0 * grid - 1.0
      output_maps = self._grid_sample(input, grid, canvas=None)
      return output_maps
  
imports: import itertools
  from typing import Dict, List, Optional, Tuple, Union
  import numpy
  import torch
  import torch.nn
  import torch.nn.functional
  from mmcv.cnn import ConvModule
  from mmocr.registry import MODELS
  from .base import BasePreprocessor
label_desc: Use image node_id 2 for calling the TPStransform obj's underlying member method code with example usage: obj.forward(input, source_control_points) and returns: output_maps