docstr: TODO: Make the model naming structure more explicit.
  TODO: Create more explicit documentation for callbacks.
docstr_tok: ["TODO",":","Make","the","model","naming","structure","more","explicit",".","TODO",":","Create","more","explicit","documentation","for","callbacks","."]
code: def train(
      self,
      training_data_collection,
      validation_data_collection=None,
      **kwargs,
  ):
      """TODO: Make the model naming structure more explicit.
      TODO: Create more explicit documentation for callbacks.
      """
  
      self.init_training(training_data_collection, kwargs)
  
      if not os.path.exists(self.output_model_filepath):
          os.mkdir(self.output_model_filepath)
  
      self.callback_process("on_train_begin")
  
      # Some explanation on training stages: The progressive gan trains each resolution
      # in two stages. One interpolates from the previous resolution, while one trains
      # solely on the current resolution. The loop below looks odd because the lowest
      # resolution only has one stage.
  
      for self.training_stage in range(
          int(np.ceil((self.starting_depth - 1) / 2)),
          (self.depth * 2) - 1,
      ):
          if self.training_stage % 2 == 0:
              self.transition = False
          else:
              self.transition = True
  
          current_depth = np.ceil((self.training_stage + 2) / 2)
          previous_depth = np.ceil((self.training_stage + 1) / 2)
          self.progressive_depth = int(current_depth)
  
          current_model_path = os.path.join(
              self.output_model_filepath,
              "{}{}".format(
                  str(current_depth),
                  self.transition_dict[self.transition],
              ),
              "model.ckpt",
          )
          if not os.path.exists(os.path.dirname(current_model_path)):
              os.mkdir(os.path.dirname(current_model_path))
  
          previous_model_path = os.path.join(
              self.output_model_filepath,
              "{}{}".format(
                  str(previous_depth),
                  self.transition_dict[not self.transition],
              ),
              "model.ckpt",
          )
  
          self.callback_process(
              "on_depth_begin", [current_depth, self.transition]
          )
  
          self.init_sess()
          self.build_tensorflow_model(self.training_batch_size)
          self.init = tf.global_variables_initializer()
          self.sess.run(self.init)
  
          if self.transition:
              self.r_saver.restore(self.sess, previous_model_path)
              self.rgb_saver.restore(self.sess, previous_model_path)
          elif self.training_stage > int(
              np.ceil((self.starting_depth - 1) / 2)
          ):
              self.saver.restore(self.sess, previous_model_path)
  
          for epoch in range(self.num_epochs):
              print(
                  (
                      "Depth {}/{}, Epoch {}/{}".format(
                          self.progressive_depth,
                          self.depth,
                          epoch + 1,
                          self.num_epochs,
                      )
                  )
              )
              self.callback_process(
                  "on_epoch_begin",
                  "_".join([str(current_depth), str(epoch)]),
              )
  
              step_counter = tqdm(
                  list(range(self.training_steps_per_epoch)),
                  total=self.training_steps_per_epoch,
                  unit="step",
                  desc="Generator Loss:",
                  miniters=1,
              )
  
              for step in step_counter:
                  self.callback_process("on_batch_begin", step)
  
                  reference_data = self.process_step(
                      step_counter, step, epoch
                  )
  
                  self.callback_process("on_batch_end", step)
  
              self.callback_process(
                  "on_epoch_end", [str(epoch), reference_data]
              )
  
              self.saver.save(self.sess, current_model_path)
  
          self.callback_process(
              "on_depth_end", [current_depth, self.transition]
          )
  
          self.saver.save(self.sess, current_model_path)
  
          self.sess.close()
          tf.reset_default_graph()
  
      # Should this be called after each progression, or after all training?
      self.callback_process("on_train_end")
  
      return
  
imports: import math
  import numpy
  import tensorflow
  import os
  import imageio
  import keras
  import scipy
  from tqdm import tqdm
  from collections import defaultdict
  from deepneuro.utilities.util import add_parameter
  from deepneuro.models.blocks import generator, discriminator
  from deepneuro.models.cost_functions import wasserstein_loss
  from deepneuro.models.gan import GAN
  from deepneuro.models.ops import upscale2d, downscale2d
  from deepneuro.utilities.visualize import check_data
label_desc: Use image node_id 4 for calling the PGGAN obj's underlying member method code with example usage: obj.train(training_data_collection, validation_data_collection) without return types