text: # Copyright 2021 Alibaba Group Holding Limited. All Rights Reserved.
  
  import torch.nn as nn
  import os
  import matplotlib.pyplot as plt
  
  
  class Visualize3DModule(nn.Module):
      def __init__(self, visualize=False, visualize_output_dir=""):
          super(Visualize3DModule, self).__init__()
          self.visualize = visualize
          self.visualize_output_dir = visualize_output_dir
          self.id = 0
  
      def visualize_features(self, module, input_x, output_x):
          """
          Visualizes and saves the normalized output features for the module.
          """
          if not self.visualize:
              return
          b, c, t, h, w = output_x.shape
          xmin, xmax = output_x.min(1).values.unsqueeze(1), output_x.max(1).values.unsqueeze(1)
          x_vis = ((output_x.detach() - xmin) / (xmax - xmin)).permute(0, 1, 3, 2, 4) \
              .reshape(b, c * h, t * w).detach().cpu().numpy()
          if hasattr(self, "stage_id"):
              stage_id = self.stage_id
              block_id = self.block_id
          else:
              stage_id = 0
              block_id = 0
          for i in range(b):
              if not os.path.exists(f'{self.visualize_output_dir}/im_{self.id + i}/'):
                  os.makedirs(f'{self.visualize_output_dir}/im_{self.id + i}/')
              plt.imsave(
                  f'{self.base_output_dir}/'
                  f'im_{self.id + i}/layer_{stage_id}_{block_id}_feature.jpg',
                  x_vis[i]
              )
          self.id += b
  
      def set_stage_block_id(self, stage_id, block_id):
          setattr(self, "stage_id", stage_id)
          setattr(self, "block_id", block_id)
  