class Initializer:
  def __init__(self):
    self.status = False
    self.sess = None
    self.threads = None
    self.coord = None
    self.saver = None
    self.saver_restore = None
    self.itr_start = 0

  def start_session(self):
    """Starts a session and initializes all variables. Provides access to session and coordinator"""
    # Start Session and initialize variables
    self.status = True

    init_op = tf.group(tf.global_variables_initializer(), tf.local_variables_initializer())

    self.sess = tf.Session()
    self.sess.run(init_op)

    # Start input enqueue threads
    self.coord = tf.train.Coordinator()
    self.threads = tf.train.start_queue_runners(sess=self.sess, coord=self.coord)

  def stop_session(self):
    """Stops a current session."""
    if self.sess and self.coord:
      self.coord.join(self.threads)
      self.sess.close()
      self.status = False

  def start_saver(self):
    """Constructs a saver and if pretrained model given, loads the model."""
    print('Constructing saver')
    self.saver = tf.train.Saver(max_to_keep=0)

    # restore dumped model if provided
    if FLAGS.pretrained_model:
      print('Restore model from: ' + str(FLAGS.pretrained_model))
      latest_checkpoint = tf.train.latest_checkpoint(FLAGS.pretrained_model)
      self.itr_start = get_iter_from_pretrained_model(latest_checkpoint) + 1
      print('Start with iteration: ' + str(self.itr_start))

      if FLAGS.exclude_from_restoring is not None:
        vars_to_exclude = str(FLAGS.exclude_from_restoring).replace(' ','').split(',')
        global_vars = dict([(v.name, v) for v in tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope="train_model")])
        global_vars = remove_items_from_dict(global_vars, vars_to_exclude)
        self.saver_restore = tf.train.Saver(var_list=list(global_vars.values()), max_to_keep=0)
        self.saver_restore.restore(self.sess, latest_checkpoint)
      else:
        self.saver.restore(self.sess, latest_checkpoint)

    return self.saver def create_model(mode=None, train_model_scope=None):
  model = None

  if mode is "train":
    model = TrainModel('train', scope_name='train_model')
  elif mode is 'valid':
    assert train_model_scope is not None, "train_model_scope is None, valid mode requires a train scope"
    model = ValidationModel('valid', reuse_scope=train_model_scope)
  elif mode is 'feeding':
    assert train_model_scope is not None, "train_model_scope is None, valid mode requires a train scope"
    model = FeedingValidationModel(reuse_scope=train_model_scope)

  assert model is not None

  return model def train(output_dir, initializer, train_model, val_model):
  assert train_model is not None and val_model is not None and initializer is not None

  saver = initializer.start_saver()

  summary_writer = tf.summary.FileWriter(output_dir, graph=initializer.sess.graph, flush_secs=10)

  tf.logging.set_verbosity(tf.logging.INFO)
  tf.logging.info(' --- Start Training --- ')
  tf.logging.info(' Iteration, Train_Loss ')

  elapsed_time = 0

  ''' main training loop '''
  try:
    for itr in range(initializer.itr_start, initializer.itr_start + FLAGS.num_iterations):
      try:
        if initializer.coord.should_stop():
          break

        #Training Step on batch
        learning_rate = helpers.learning_rate_decay(FLAGS.learning_rate, itr, decay_factor=FLAGS.learning_rate_decay)
        feed_dict = {train_model.learning_rate: learning_rate, train_model.elapsed_time: float(elapsed_time)}

        t = time.time()
        train_loss, _, train_summary_str = initializer.sess.run([train_model.loss, train_model.train_op, train_model.sum_op], feed_dict)
        elapsed_time = time.time() - t

        #validation
        if itr % FLAGS.valid_interval == 1:

          feed_dict = {val_model.learning_rate: 0.0}

          # summary and log
          val_loss, val_summary_str = initializer.sess.run([val_model.loss, val_model.sum_op], feed_dict)

          summary_writer.add_summary(val_summary_str, itr)

          #Print validation loss
          tf.logging.info(' Validation loss at step ' + str(itr) + ':    ' + str(val_loss))

        #dump summary
        if itr % FLAGS.summary_interval == 1:
          summary_writer.add_summary(train_summary_str, itr)

        #save model checkpoint
        if itr % FLAGS.save_interval == 1:
          save_path = saver.save(initializer.sess, os.path.join(output_dir, 'model'), global_step=itr) #TODO also implement save operation in Initializer class
          tf.logging.info('Saved Model to: ' + str(save_path))

        #Print iteration and loss
        tf.logging.info(' ' + str(itr) + ':    ' + str(train_loss) + ' | %.2f sec'%(elapsed_time))
      except Exception as e:
        tf.logging.info('Training iteration ' + str(itr) + 'failed: ' + str(e.message))
  except tf.errors.OutOfRangeError:
    tf.logging.info('Done training -- iterations limit reached')
  finally:
    # When done, ask the threads to stop.
    initializer.coord.request_stop()

  tf.logging.info(' Saving Model ... ')
  saver.save(initializer.sess, os.path.join(output_dir, 'model'), global_step=initializer.itr_start + FLAGS.num_iterations)

  # necessary for outer (train manager) loop to prevent variable conflicts with previously used graph
  tf.reset_default_graph()
  # Wait for threads to finish.
  initializer.stop_session() def validate(output_dir, initializer, val_model):
  """ feeds validation batch through the model and stores produced frame sequence as gifs to output_dir
    :param
      output_dir: path to output directory where validation summary and gifs are stored
  """
  assert val_model is not None and initializer is not None

  if initializer.saver is None:
    initializer.start_saver()

  # Calculate number of validation samples
  valid_filenames = file_paths_from_directory(FLAGS.tf_records_dir, 'valid*')
  num_valid_samples = input.get_number_of_records(valid_filenames)
  print('Detected %i validation samples' % num_valid_samples)


  tf.logging.info(' --- Start validation --- ')

  try:
    feed_dict = {val_model.learning_rate: 0.0}
    num_val_batches_required = (num_valid_samples // (FLAGS.valid_batch_size * FLAGS.num_gpus)) + int(
        (num_valid_samples % (FLAGS.valid_batch_size * FLAGS.num_gpus)) != 0)

    if not 'measure_test_time' in FLAGS.valid_mode:
      val_loss, val_summary_str, output_frames, hidden_representations, labels, metadata, orig_frames = initializer.sess.run(
        [val_model.loss, val_model.sum_op, val_model.output_frames, val_model.hidden_repr, val_model.label, val_model.metadata, val_model.val_batch], feed_dict)


    if 'vector' in FLAGS.valid_mode:
      # store encoder latent vector for analysing

      hidden_repr_dir = create_subfolder(output_dir, 'hidden_repr')
      store_encoder_latent_vector(hidden_repr_dir, hidden_representations, labels, True)

    if 'gif' in FLAGS.valid_mode:
      # summary and log
      val_model.iter_num = 1
      createGif(np.asarray(orig_frames)[:, FLAGS.image_range_start:FLAGS.image_range_start + FLAGS.encoder_length + FLAGS.decoder_future_length,:,:,:3], labels, output_dir)
      tf.logging.info('Converting validation frame sequences to gif')
      store_output_frames_as_gif(np.asarray(output_frames)[:,:,:,:,:3], labels, output_dir)
      tf.logging.info('Dumped validation gifs in: ' + str(output_dir))

    if 'similarity' in FLAGS.valid_mode:
      print(str(similarity_computations.compute_hidden_representation_similarity(hidden_representations, labels, 'cos')))

    if 'memory_prep' in FLAGS.valid_mode:
      # evaluate multiple batches to cover all available validation samples
      video_file_path = []

      for i in range(num_val_batches_required):
        hidden_representations_new, labels_new, metadata_new, orig_frames = initializer.sess.run(
          [val_model.hidden_repr, val_model.label, val_model.metadata, val_model.val_batch], feed_dict)

        video_file_path.extend(["original_clip_%s.gif" % str(l.decode('utf-8')) for l in labels])
        hidden_representations = np.concatenate((hidden_representations, hidden_representations_new))
        labels = np.concatenate((labels, labels_new))
        metadata = np.concatenate((metadata, metadata_new))
        createGif(np.asarray(orig_frames)[:,:,:, :, :3], labels, output_dir)

      store_latent_vectors_as_df(output_dir, hidden_representations, labels, metadata, video_file_paths=np.asarray(video_file_path))

    if 'data_frame' in FLAGS.valid_mode:
      print(np.shape(hidden_representations))
      #evaluate multiple batches to cover all available validation samples
      for i in range(num_val_batches_required):
        hidden_representations_new, labels_new, metadata_new = initializer.sess.run([val_model.hidden_repr, val_model.label, val_model.metadata], feed_dict)
        hidden_representations = np.concatenate((hidden_representations, hidden_representations_new))
        labels = np.concatenate((labels, labels_new))
        metadata = np.concatenate((metadata, metadata_new))

      print(np.shape(hidden_representations))
      store_latent_vectors_as_df(output_dir, hidden_representations, labels, metadata)

    if 'psnr' in FLAGS.valid_mode:
      log_file = os.path.join(output_dir, 'psnr_log_' + str(dt.datetime.now()) + ".txt")

      mean_psnr_reconstruction_means = []
      mean_psnr_rec_stds = []

      mean_psnr_future_means = []
      mean_psnr_fut_stds = []

      mean_orig_rec_color_means = []
      mean_orig_rec_color_std = []

      mean_orig_fut_color_means = []
      mean_orig_fut_color_std = []

      mean_orig_rec_rand_means = []
      mean_orig_rec_rand_std = []

      mean_orig_fut_rand_means = []
      mean_orig_fut_rand_std = []


      psnr_reconstruction = []
      psnr_future = []

      orig_rec_rand_mean = []
      orig_fut_rand_mean = []

      orig_rec_video_color_mean = []
      orig_fut_video_color_mean = []


      for i in range(num_val_batches_required):
        print("processing batch " + str(i+1) + " of " + str(num_val_batches_required) + " total batches.")
        output_frames, orig_frames = initializer.sess.run([val_model.output_frames, val_model.val_batch], feed_dict)
        video_count = orig_frames.shape[0]

        for i in range(video_count):
          orig_rec_video_frames = np.asarray(orig_frames)[i, (FLAGS.image_range_start + FLAGS.encoder_length - FLAGS.decoder_reconst_length): (FLAGS.image_range_start +FLAGS.encoder_length), :, :, :3]
          orig_fut_video_frames = np.asarray(orig_frames)[i, (FLAGS.image_range_start + FLAGS.encoder_length):(FLAGS.image_range_start + FLAGS.encoder_length + FLAGS.decoder_future_length), :, :, :3]
          recon_video_frames = np.asarray(output_frames)[(FLAGS.encoder_length - FLAGS.decoder_reconst_length):FLAGS.encoder_length, i, :, :, :3]
          recon_video_frames = recon_video_frames.astype('uint8')
          future_video_frames = np.asarray(output_frames)[(FLAGS.encoder_length):(FLAGS.encoder_length + FLAGS.decoder_future_length), i, :, :, :3]
          future_video_frames = future_video_frames.astype('uint8')

          #for j in range(recon_video_frames.shape[0]):
          #  plt.imsave(os.path.join(output_dir, 'pic_' + str(i) + "_" + str(j)), recon_video_frames[j])


          """ encoder/decoder frames """
          psnr_reconstruction.append(np.asarray([metrics.peak_signal_to_noise_ratio(orig_frame, bgr_to_rgb(recon_frame), color_depth=255) for orig_frame, recon_frame in zip(orig_rec_video_frames, recon_video_frames)]))
          psnr_future.append(np.asarray([metrics.peak_signal_to_noise_ratio(orig_fut_frame, bgr_to_rgb(fut_frame), color_depth=255) for orig_fut_frame, fut_frame in zip(orig_fut_video_frames, future_video_frames)]))


          """ mean baseline computations """
          video_meaned_rec = orig_rec_video_frames.mean(axis=(0, 1, 2), keepdims=True)
          mean_video_rec = np.tile(video_meaned_rec, (orig_rec_video_frames.shape[0], FLAGS.width, FLAGS.height, 1))


          orig_rec_video_color_mean.append(np.asarray([metrics.peak_signal_to_noise_ratio(mean_frame, bgr_to_rgb(orig_rec_frame), color_depth=255)
                                                 for mean_frame, orig_rec_frame in zip(mean_video_rec, orig_rec_video_frames)]))

          orig_fut_video_color_mean.append(np.asarray([metrics.peak_signal_to_noise_ratio(mean_frame, bgr_to_rgb(orig_fut_frame), color_depth=255)
                                                for mean_frame, orig_fut_frame in zip(mean_video_rec, orig_fut_video_frames)]))


          """ random image baseline computations """
          rand_frames = np.random.randint(0, 255, (recon_video_frames.shape[0], FLAGS.width, FLAGS.height, FLAGS.num_depth))

          orig_rec_rand_mean.append(np.asarray([metrics.peak_signal_to_noise_ratio(rand_frame, bgr_to_rgb(orig_rec_frame), color_depth=255)
                                                for rand_frame, orig_rec_frame in zip(rand_frames, orig_rec_video_frames)]))

          orig_fut_rand_mean.append(np.asarray([metrics.peak_signal_to_noise_ratio(rand_frame, bgr_to_rgb(fut_frame), color_depth=255)
                                                for rand_frame, fut_frame in zip(rand_frames, orig_fut_video_frames)]))

      psnr_reconstruction_means = np.mean(np.stack(psnr_reconstruction), axis=0)
      psnr_rec_stds = np.std(np.stack(psnr_reconstruction), axis=0)

      psnr_future_means = np.mean(np.stack(psnr_future), axis=0)
      psnr_fut_stds = np.std(np.stack(psnr_future), axis=0)

      orig_rec_color_means = np.mean(np.stack(orig_rec_video_color_mean), axis=0)
      orig_rec_color_std = np.std(np.stack(orig_rec_video_color_mean), axis=0)

      orig_fut_color_means = np.mean(np.stack(orig_fut_video_color_mean), axis=0)
      orig_fut_color_std = np.std(np.stack(orig_fut_video_color_mean), axis=0)

      orig_rec_rand_means = np.mean(np.stack(orig_rec_rand_mean), axis=0)
      orig_rec_rand_std = np.std(np.stack(orig_rec_rand_mean), axis=0)

      orig_fut_rand_means = np.mean(np.stack(orig_fut_rand_mean), axis=0)
      orig_fut_rand_std = np.std(np.stack(orig_fut_rand_mean), axis=0)


      """ gather values for computing means over several runs """
      mean_psnr_reconstruction_means.append(psnr_reconstruction_means)
      mean_psnr_rec_stds.append(psnr_rec_stds)

      mean_psnr_future_means.append(psnr_future_means)
      mean_psnr_fut_stds.append(psnr_fut_stds)

      mean_orig_rec_color_means.append(orig_rec_color_means)
      mean_orig_rec_color_std.append(orig_rec_color_std)

      mean_orig_fut_color_means.append(orig_fut_color_means)
      mean_orig_fut_color_std.append(orig_fut_color_std)

      mean_orig_rec_rand_means.append(orig_rec_rand_means)
      mean_orig_rec_rand_std.append(orig_rec_rand_std)

      mean_orig_fut_rand_means.append(orig_fut_rand_means)
      mean_orig_fut_rand_std.append(orig_fut_rand_std)

      """ gather values for computing means over several runs """
      mean_psnr_reconstruction_means = np.mean(mean_psnr_reconstruction_means, axis=0)
      mean_psnr_rec_std = np.mean(mean_psnr_rec_stds, axis =0)

      mean_psnr_future_means = np.mean(mean_psnr_future_means, axis=0)
      mean_psnr_fut_stds = np.mean(mean_psnr_fut_stds, axis=0)

      mean_orig_rec_color_means = np.mean(mean_orig_rec_color_means, axis=0)
      mean_orig_rec_color_std = np.mean(mean_orig_rec_color_std, axis=0)

      mean_orig_fut_color_means = np.mean(mean_orig_fut_color_means, axis=0)
      mean_orig_fut_color_std = np.mean(mean_orig_fut_color_std, axis=0)

      mean_orig_rec_rand_means = np.mean(mean_orig_rec_rand_means, axis=0)
      mean_orig_rec_rand_std = np.mean(mean_orig_rec_rand_std, axis=0)

      mean_orig_fut_rand_means = np.mean(mean_orig_fut_rand_means, axis=0)
      mean_orig_fut_rand_std = np.mean(mean_orig_fut_rand_std, axis=0)


      write_file_with_append(log_file, "mean psnr recon: " + str(mean_psnr_reconstruction_means) + "\nmean psnr future: " + str(mean_psnr_future_means) +
                                      "\nstd psnr recon: " + str(mean_psnr_rec_std) + "\nstd psnr future: " + str(mean_psnr_fut_stds) +
                                      "\nmean of psnr between color mean of original rec frames and recon frames: " + str(mean_orig_rec_color_means) + "\nmean of psnr between color mean of original fut frames and fut frames: " + str(mean_orig_fut_color_means) +
                                      "\nstd of psnr between color mean of original rec frames recond frames: " + str(mean_orig_rec_color_std) + "\nstd of psnr between color mean of original fut frames and fut frames: " + str(mean_orig_fut_color_std) +
                                      "\nmean of psnr between random image and rec frames: " + str(mean_orig_rec_rand_means) + "\nmean of psnr between random image and fut frames: " + str(mean_orig_fut_rand_means) +
                                      "\nstd of psnr between random image and rec frames: " + str(mean_orig_rec_rand_std) + "\nstd of psnr between random image and fut frames: " + str(mean_orig_fut_rand_std)

                             )

      print("mean psnr recon: " + str(mean_psnr_reconstruction_means) + "\nmean psnr future: " + str(mean_psnr_future_means))
      tf.logging.info('Added psnr values to log file ' + str(log_file))

    if 'count_trainable_weights' in FLAGS.valid_mode:
      total_parameters = 0
      for variable in tf.trainable_variables():
        # shape is an array of tf.Dimension
        shape = variable.get_shape()
        print(shape)
        print(len(shape))
        variable_parameters = 1
        for dim in shape:
          print(dim)
          variable_parameters *= dim.value
        print(variable_parameters)
        total_parameters += variable_parameters
      print("Total parameters are:" + total_parameters)

    #summary_writer.add_summary(val_summary_str, 1)

    if 'measure_test_time' in FLAGS.valid_mode:
      measure_encoder_only = True

      elapsed_time = 0
      time_array = []
      total_frames_array = []
      video_count = FLAGS.valid_batch_size
      n_frames = FLAGS.encoder_length
      now = datetime.datetime.now()

      with open('time_measurements.txt', 'a') as f:
        for i in range(num_val_batches_required):
          if not measure_encoder_only:
            headline_log = "------Encoder/Decoders time recordings in test mode (5 frames), date: " + now.strftime("%Y-%m-%d %H:%M") + "------"
            t = time.time()
            _, _ = initializer.sess.run([val_model.output_frames, val_model.val_batch], feed_dict)
            elapsed_time = time.time() - t
            time_array.append(elapsed_time)
            total_frames_array.append(video_count * n_frames)

          else:
            headline_log = "------Encoder time recordings in test mode (5 frames), date: " + now.strftime("%Y-%m-%d %H:%M") + "------"
            t = time.time()
            _ = initializer.sess.run([val_model.hidden_repr], feed_dict)
            elapsed_time = time.time() - t
            time_array.append(elapsed_time)
            total_frames_array.append(video_count * n_frames)


        total_time = np.sum(time_array, axis=0)
        total_frames = np.sum(total_frames_array, axis=0)
        fps = (total_frames / total_time)



        print("\n" + headline_log, file=f)
        print("the first 10 elapsed time records per batch: \n", time_array[:10], file=f)
        print("----", file=f)
        print("total_time in seconds: ", total_time, file=f)
        print("total frames: ", total_frames, file=f)
        print("fps:", fps, file=f)
        print("number of valid samples:", num_valid_samples, file=f)
        print("valid batch size:", FLAGS.valid_batch_size, file=f)



  except tf.errors.OutOfRangeError:
    tf.logging.info('Done producing validation results -- iterations limit reached')
  except Exception as e:
    print("Exception occured:", e)
    print(traceback.format_exc())
  finally:
    # When done, ask the threads to stop.
    initializer.coord.request_stop()

  # Wait for threads to finish.
  initializer.stop_session() def feed(feed_batch, initializer, feeding_model):
  '''
  feeds the videos inherent feed_batch trough the network provided in feed_model
  :param feed_batch: 5D Tensor (batch_size, num_frames, width, height, num_channels)
  :param initializer:
  :param feed_model:
  :return:
  '''
  assert feeding_model is not None and initializer is not None
  assert feed_batch.ndim == 5


  tf.logging.info(' --- Starting feeding --- ')

  feed_dict = {feeding_model.learning_rate: 0.0, feeding_model.feed_batch: feed_batch}

  hidden_repr = initializer.sess.run([feeding_model.hidden_repr], feed_dict)


  return hidden_repr def create_batch_and_feed(initializer, feeding_model):
  # TODO
  """

  :param initializer:
  :param feed_model:
  :return:
  """
  assert FLAGS.pretrained_model
  feed_batch = generate_batch_from_dir(FLAGS.feeding_input_dir, suffix='*.jpg')
  print("feed batch has shape: " + str(feed_batch.shape))
  hidden_repr = feed(feed_batch, initializer=initializer, feeding_model=feeding_model)

  return np.array(np.squeeze(hidden_repr)) FLAGS = flags.FLAGS class Memory:

  def __init__(self, memory_df, base_dir, label_col="category", video_path_col="video_file_path", inter_class_pca_path=None):
    ''' Initializes the Memory class
    :param memory_df: pandas dataframe that contains the hidden_reps, labels and video_paths of the episodes
    :param label_col: specifies the label column name within the df
    :param video_path_col: specifies the video path column name within the df
    :param inter_class_pca_path: specifies the path to the model object of a previously trained PCA
    '''
    assert label_col in memory_df.columns, str(label_col) + ' must be a dataframe category'
    assert isinstance(memory_df, pd.DataFrame)

    self.memory_df = memory_df
    self.hidden_reps = np.stack([h.flatten() for h in memory_df['hidden_repr']])
    self.labels = memory_df[["id", label_col]]
    self.labels.set_index('id')
    self.video_paths = memory_df[["id", video_path_col]]
    self.video_paths.set_index('id')
    self.base_dir = base_dir


    #get fitted PCA object
    if inter_class_pca_path:
      assert os.path.isfile(inter_class_pca_path)
      self.inter_class_pca = joblib.load(inter_class_pca_path)
    else:
      self.inter_class_pca = fit_inter_class_pca(self.hidden_reps, self.labels, n_components=50, verbose=False)

    # PCA transform the hidden_reps
    self.hidden_reps_transformed = self.inter_class_pca.transform(self.hidden_reps)

    self.check_memory_sanity()

  def check_memory_sanity(self):
    num_vids_found = np.sum([os.path.isfile( os.path.join(self.base_dir, v_path) ) for v_path in self.video_paths["video_file_path"].values])
    num_episodes = self.labels.shape[0]
    print("Memory contains %i episodes. Video file exists for %i out of %i episodes" % (num_episodes, num_vids_found, num_episodes))

  def store_episodes(self, ids, hidden_reps, metadata_dicts, video_file_paths):
    '''
    stores provided episodes in mongo database (memory)
    :param ids:
    :param hidden_reps:
    :param metadata_dicts:
    :param video_file_path:
    :return mongodb_ids corresponding to the persisted documents
    '''
    assert len(ids) == len(hidden_reps) == len(metadata_dicts) == len(video_file_paths)
    assert all([os.path.isfile(path) for path in video_file_paths])

    #TODO: store as document in mongodb

    #for i, id in enumerate(ids):
    #  if id not in self.memory_df:

  def get_episode(self, id):
    '''
    queries a single episode by its id
    :return: tuple of four objects (id, hidden_reps, metadata_dicts, video_episode)
    '''
    # TODO
    #pass

  def matching(self, query_hidden_repr, n_closest_matches = 5, use_transform=False):
    '''
    finds the closest vector matches (cos_similarity) for a given query vector
    :param query_hidden_repr: the query vector
    :param n_clostest_matches: (optional) the number of closest matches returned, defaults to 5
    :param use_transform: boolean that denotes whether the matching shall performed on transformed hidden vectors
    :return: four arrays, containing:
          1. the n_clostest_matches by id
          2. the n_closest_matches by computed pairwise cos distance
          3. the n_closest_matches hidden representations
          4. the n_closest_matches absolute paths to the memory episodes in the base directory of the memory
    '''

    query_hidden_repr = np.expand_dims(query_hidden_repr, axis=0)
    if use_transform:
      memory_hidden_reps = self.hidden_reps_transformed
      query_hidden_repr = self.inter_class_pca.transform(query_hidden_repr)
    else:
      memory_hidden_reps = self.hidden_reps
    assert memory_hidden_reps.ndim == 2 #memory_hidden_reps must have shape (n_episodes, n_dim_repr)
    assert query_hidden_repr.ndim == 2 #query_hidden_repr must have shape (1, n_dim_repr)
    assert memory_hidden_reps.shape[1] == query_hidden_repr.shape[1]

    cos_distances = pairwise_distances(memory_hidden_reps, query_hidden_repr, metric='cosine')[:,0] #shape(n_episodes, 1)
    # get indices of n maximum values in ndarray, reverse the list (highest is leftmost)
    indices_closest = cos_distances.argsort()[:-n_closest_matches:-1]

    relative_paths = self.video_paths.iloc[indices_closest]["video_file_path"].values
    absolute_paths = [os.path.join(self.base_dir, path) for i, path in enumerate(relative_paths)]

    return indices_closest, cos_distances[indices_closest], memory_hidden_reps[indices_closest], absolute_paths def create_session_dir(output_dir): #TODO move to utils
  assert(output_dir)
  dir_name = str(dt.datetime.now().strftime("%m-%d-%y_%H-%M"))
  output_dir = os.path.join(output_dir, dir_name)
  if not os.path.isdir(output_dir):
    os.mkdir(output_dir)
  print('Created custom directory for session:', dir_name)
  return output_dir def create_subfolder(dir, name):
  subdir = os.path.join(dir, name)
  if not os.path.isdir(subdir):
    os.mkdir(subdir)
    print('Created subdir:', subdir)
    return subdir
  else:
    return os.path.join(dir, name) def write_metainfo(output_dir, model_name, flags):
  with open(os.path.join(output_dir, 'metainfo.txt'), 'a') as f:
    f.write('\n' + '---- Training: ' + str(dt.datetime.now()) + ' ----' + '\n')
    f.write('model' + ':  ' + str(os.path.basename(model_name)) + '\n') #print model name
    for key, value in flags.__flags.items():
      f.write(str(key) + ':  ' + str(value) + '\n') def generate_batch_from_dir(path, suffix="*.png"):
  '''
  :param path: directory path to images
  :param suffix: regex that specifies the file suffix (e.g. "*.png" or "*.jpg")
  :return: numpy array with shape (1, encoder_length, height, width, num_channels)
  '''
  assert os.path.isdir(path), str(path) + "doesn't seem to be a valid path"

  files = file_paths_from_directory(path, suffix)
  assert files and len(files)>0, 'Could not find an image with suffix %s in %s'%(path, suffix)
  batch = np.zeros((1, FLAGS.encoder_length, FLAGS.height, FLAGS.width, 3), dtype=np.uint8)

  for i, filename in enumerate(files[:FLAGS.encoder_length]):
    im = Image.open(filename).convert('RGB')
    if im.size != (FLAGS.height, FLAGS.width):
      im = im.resize((FLAGS.height, FLAGS.width), Image.ANTIALIAS)
      print("image " + str(filename) + " has a different shape than expected -> reshape to (%i,%i)"%(FLAGS.height, FLAGS.width))
    batch[0, i, :, :, :3] = np.asarray(im, np.uint8)


  # add dense optical flow channel to batch
  if FLAGS.num_channels == 4:
    batch = compute_dense_optical_flow_for_batch(batch)

  return batch
import tensorflow as tf
import pandas as pd
import numpy as np
from tensorflow.python.platform import app
from core.Initializer import Initializer
from core.Model import create_model
from core.development_op import train, validate
from core.production_op import feed, create_batch_and_feed
from settings import FLAGS
from core.Memory import Memory
from utils.io_handler import create_session_dir, create_subfolder, write_metainfo, generate_batch_from_dir



def main(argv):
  # train model is required in every case
  train_model = create_model(mode='train')
  if FLAGS.mode is "train_mode" or FLAGS.mode is "valid_mode":
    val_model = create_model(mode='valid', train_model_scope=train_model.scope)
  elif FLAGS.mode is "feeding_mode":
    feeding_model = create_model(mode='feeding', train_model_scope=train_model.scope)

  initializer = Initializer()
  initializer.start_session()
  initializer.start_saver()

  # ---- training ----- #
  if FLAGS.mode is "train_mode":
    """either create new directory or reuse old one"""
    if not FLAGS.pretrained_model:
      output_dir = create_session_dir(FLAGS.output_dir)
    else:
      output_dir = FLAGS.pretrained_model
      print('Reusing provided session directory:', output_dir)

    tf.logging.info(' --- ' + FLAGS.mode.capitalize() + ' --- ')
    write_metainfo(output_dir, train_model.model_name, FLAGS)

    train(output_dir, initializer, train_model, val_model)