class_docstr: The basic implementation for self-attention block/non-local block
  Input:
      N X C X H X W
  Parameters:
      in_channels       : the dimension of the input feature map
      key_channels      : the dimension after the key/query transform
      value_channels    : the dimension after the value transform
      scale             : choose the scale to downsample the input feature maps
  Return:
      N X C X H X W
      position-aware context features.(w/o concate or add with the input)
code: def forward(self, x):
      batch_size, _, h, w = x.size(0), x.size(1), x.size(2), x.size(3)
  
      local_x = []
      local_y = []
      step_h, step_w = h // self.scale, w // self.scale
      for i in range(0, self.scale):
          for j in range(0, self.scale):
              start_x, start_y = i * step_h, j * step_w
              end_x, end_y = min(start_x + step_h, h), min(
                  start_y + step_w, w
              )
              if i == (self.scale - 1):
                  end_x = h
              if j == (self.scale - 1):
                  end_y = w
              local_x += [start_x, end_x]
              local_y += [start_y, end_y]
  
      value = self.f_value(x)
      query = self.f_query(x)
      key = self.f_key(x)
  
      local_list = []
      local_block_cnt = 2 * self.scale * self.scale
      for i in range(0, local_block_cnt, 2):
          value_local = value[
              :,
              :,
              local_x[i] : local_x[i + 1],
              local_y[i] : local_y[i + 1],
          ]
          query_local = query[
              :,
              :,
              local_x[i] : local_x[i + 1],
              local_y[i] : local_y[i + 1],
          ]
          key_local = key[
              :,
              :,
              local_x[i] : local_x[i + 1],
              local_y[i] : local_y[i + 1],
          ]
  
          h_local, w_local = value_local.size(2), value_local.size(3)
          value_local = value_local.contiguous().view(
              batch_size, self.value_channels, -1
          )
          value_local = value_local.permute(0, 2, 1)
  
          query_local = query_local.contiguous().view(
              batch_size, self.key_channels, -1
          )
          query_local = query_local.permute(0, 2, 1)
          key_local = key_local.contiguous().view(
              batch_size, self.key_channels, -1
          )
  
          sim_map = torch.matmul(query_local, key_local)
          sim_map = (self.key_channels**-0.5) * sim_map
          sim_map = F.softmax(sim_map, dim=-1)
  
          context_local = torch.matmul(sim_map, value_local)
          context_local = context_local.permute(0, 2, 1).contiguous()
          context_local = context_local.view(
              batch_size, self.value_channels, h_local, w_local
          )
          local_list.append(context_local)
  
      context_list = []
      for i in range(0, self.scale):
          row_tmp = []
          for j in range(0, self.scale):
              row_tmp.append(local_list[j + i * self.scale])
          context_list.append(torch.cat(row_tmp, 3))
  
      context = torch.cat(context_list, 2)
      context = self.W(context)
  
      return context
  
imports: import torch
  import torch.nn.functional
  from torch import nn
  from ..modules.activations import ABN
label_desc: Use image node_id 2 for calling the _PyramidSelfAttentionBlock obj's underlying member method code with example usage: obj.forward(x) and returns: context