class_docstr: ## Hourglass model
  
  This model recursively adds layers to the middle while shortening the sequence by down-sampling.
  The shortened sequence processed by another hourglass model is sandwiched between two normal transformer
  layers. (A transformer layer has a [self-attention layer](../mha.html)
   and a [position-wise feed-forward layer](../feed_forward.html)).
code: def forward(self, x: torch.Tensor):
      # Initial transformer layer
      # $$x \leftarrow PreVanillaLayers(x)$$
      x = self.pre(x=x, mask=self.mask(x))
      # Shifting and shortening
      # $$x' \leftarrow Shortening(ShiftRight(x,k−1),k)$$
      x_short = self.shortening(self.shift_right(x))
  
      # If we are at the center of the hourglass,
      # $$\textbf{\small if } \text{\small E\scriptsize MPTY}(shorten\_factors) \textbf{\small then}$$
      if self.hour_glass is None:
          # Center transformer layer
          # $$x' \leftarrow ShortenedLayers(x')$$
          x_short = self.shortened(
              x=x_short, mask=self.mask_short(x_short)
          )
      # $$\textbf{else}$$
      else:
          # $$x' \leftarrow \text{\small H\scriptsize OURGLASS}(x, shorten\_factors)$$
          x_short = self.hour_glass(x_short)
  
      # Up-sample the shortened sequence and add a skip connection
      # $$x \leftarrow x + Upsampling(x, x', k)$$
      x = x + self.up_sampling(x, x_short)
      # Final transformer layer
      # $$x \leftarrow PostVanillaLayers(x)$$
      x = self.post(x=x, mask=self.mask(x))
  
      #
      return x
  
imports: from typing import List
  import torch
  from torch import nn
  from labml_helpers.module import Module
  from labml_nn.transformers import MultiHeadAttention, TransformerLayer
  from labml_nn.transformers.feed_forward import FeedForward
  from labml_nn.transformers.utils import subsequent_mask
label_desc: Use image node_id 2 for calling the HourGlass obj's underlying member method code with example usage: obj.forward(x) and returns: x