code: def report_theoretical_memory(
      args, num_microbatches=None, verbose=False
  ):
      # Formulae here assume sequence parallelism and selective activation recomputation.
      if (
          not args.sequence_parallel
          or args.recompute_granularity != "selective"
      ):
          return
  
      weight_and_optimizer_memory = (
          compute_weight_and_optimizer_memory(args, verbose=verbose)
          / NUM_BYTES_IN_MEGABYTE
      )
      activation_memory = (
          compute_activation_memory(
              args, num_microbatches=num_microbatches, verbose=verbose
          )
          / NUM_BYTES_IN_MEGABYTE
      )
      total_memory = weight_and_optimizer_memory + activation_memory
  
      print(
          f"Theoretical memory footprints: weight and optimizer={weight_and_optimizer_memory:.2f} MB, "
          f"activation={activation_memory:.2f} MB, "
          f"total={total_memory:.2f} MB\n"
      )
  
imports: import math
label_desc: Use image node_id 3 for calling a global function with example usage: report_theoretical_memory(args, num_microbatches, verbose) without return types