//  [python]
def train_loop(opts, graph, loss, train_dataset, training_pl, handle_pl, train_op,
               train_summary_op, test_summary_op,
               num_steps,
               global_step, checkpoint_fname,
               test_dataset=None,
               ignore_missing_vars=False,
               reset_global_step=False, vars_to_restore=None,
               exclude_vars=None, fwd_only=False, allow_growth=False):
  """
  training loop without a supervisor:
  """
  tf.logging.set_verbosity(tf.logging.INFO)
  with graph.as_default(), tf.device('/cpu:0'):
    # define iterators
    train_iterator = train_dataset.make_initializable_iterator()
    if test_dataset:
      test_iterator = test_dataset.make_initializable_iterator()

    session_config = tf.ConfigProto(allow_soft_placement=True,log_device_placement=False)
    session_config.gpu_options.allow_growth = allow_growth
    session = tf.Session(config=session_config)

    global_init = tf.initialize_all_variables()
    local_init = tf.local_variables_initializer()
    session.run([global_init,local_init])

    # set up iterators
    train_handle = session.run(train_iterator.string_handle())
    session.run(train_iterator.initializer)
    if test_dataset:
      test_handle = session.run(test_iterator.string_handle())

    # check if we need to restore the model:
    if tf.gfile.Exists(checkpoint_fname) or tf.gfile.Exists(checkpoint_fname+'.index'):
      print(colorize('RESTORING MODEL from: '+checkpoint_fname, 'blue', bold=True))
      if not isinstance(vars_to_restore,list):
        if vars_to_restore == 'all':
          vars_to_restore = tf.global_variables()
        elif vars_to_restore == 'model':
          vars_to_restore = tf.get_collection(tf.GraphKeys.MODEL_VARIABLES)
      if reset_global_step >= 0:
        print(colorize('Setting global-step to %d.'%reset_global_step,'red',bold=True))
        var_names = [v.name for v in vars_to_restore]
        reset_vid = [i for i in xrange(len(var_names)) if 'global_step' in var_names[i]]
        if reset_vid:
          vars_to_restore.pop(reset_vid[0])
      print(colorize('vars-to-be-restored:','green',bold=True))
      print(colorize(', '.join([v.name for v in vars_to_restore]),'green'))
      if ignore_missing_vars:
        reader = tf.train.NewCheckpointReader(checkpoint_fname)
        checkpoint_vars = reader.get_variable_to_shape_map().keys()
        vars_ignored = [v.name for v in vars_to_restore if v.name[:-2] not in checkpoint_vars]
        print(colorize('vars-IGNORED (not restoring):','blue',bold=True))
        print(colorize(', '.join(vars_ignored),'blue'))
        vars_to_restore = [v for v in vars_to_restore if v.name[:-2] in checkpoint_vars]
      if exclude_vars:
        for exclude_var_name in exclude_vars:
          var_names = [v.name for v in vars_to_restore]
          reset_vid = [i for i in xrange(len(var_names)) if exclude_var_name in var_names[i]]
          if reset_vid:
            vars_to_restore.pop(reset_vid[0])
      restorer = tf.train.Saver(var_list=vars_to_restore)
      restorer.restore(session,checkpoint_fname)

    # create a summary writer:
    summary_writer = tf.summary.FileWriter(opts['log_dir'], graph=session.graph)
    # create a check-pointer:
    #  --> keep ALL the checkpoint files:
    saver = tf.train.Saver(tf.global_variables(), max_to_keep=None)

    # get the value of the global-step:
    start_step = session.run(global_step)
    # run the training loop:
    begin_time = time.time()
    for step in xrange(start_step, num_steps):
      start_time = time.time()
      if fwd_only:  # useful for timing..
        feed_dict = {handle_pl: train_handle, training_pl: False}
        loss_value = session.run(loss, feed_dict=feed_dict)
      else:
        feed_dict = {handle_pl: train_handle, training_pl: True}
        if step % opts['n_summary'] == 0:
          loss_value, _, summary_str = session.run([loss, train_op,
                                                    train_summary_op],
                                                   feed_dict=feed_dict)
          summary_writer.add_summary(summary_str, step)
          summary_writer.flush() # write to disk now
        else:
          loss_value, _ = session.run([loss, train_op], feed_dict=feed_dict)
      duration = time.time() - start_time

      # make sure that we have non NaNs:
      assert not np.isnan(loss_value), 'Model diverged with loss = NaN'

      # print stats for this batch:
      examples_per_sec = opts['batch_size'] / float(duration)
      format_str = '%s: step %d, loss = %.4f (%.1f examples/sec) %.3f sec/batch'
      tf.logging.info(format_str % (datetime.now(), step, loss_value,
                      examples_per_sec, duration))

      # periodically test on test set
      if not fwd_only and test_dataset and step % opts['n_test'] == 0:
        feed_dict = {handle_pl: test_handle, training_pl: False}
        metrics_reset_ops = tf.get_collection('metrics_reset')
        metrics_update_ops = tf.get_collection('metrics_update')
        session.run(metrics_reset_ops)
        session.run(test_iterator.initializer)
        test_iter = 0
        while True:
          try:
            start_time = time.time()
            if test_iter == 0:
              loss_value, summary_str, _ = session.run(
                [loss, test_summary_op, metrics_update_ops],
                feed_dict=feed_dict)
              summary_writer.add_summary(summary_str, step)
            else:
              loss_value, _ = session.run(
                [loss, metrics_update_ops], feed_dict=feed_dict)
            duration = time.time() - start_time

            examples_per_sec = opts['batch_size'] / float(duration)
            format_str = 'test: %s: step %d, loss = %.4f (%.1f examples/sec) %.3f sec/batch'
            tf.logging.info(format_str % (datetime.now(), step, loss_value,
                            examples_per_sec, duration))
          except tf.errors.OutOfRangeError:
            print('iteration through test set finished')
            break
          test_iter += 1

        metrics_summaries_ops = tf.get_collection('metrics_summaries')
        if metrics_summaries_ops:
          summary_str = session.run(tf.summary.merge(metrics_summaries_ops))
          summary_writer.add_summary(summary_str, step)

        summary_writer.flush() # write to disk now

      # periodically write the summary (after every N_SUMMARY steps):
      if not fwd_only:
        # periodically checkpoint:
        if step % opts['n_checkpoint'] == 0:
          checkpoint_path = osp.join(opts['log_dir'],'model.ckpt')
          saver.save(session, checkpoint_path, global_step=step)
    total_time = time.time()-begin_time
    samples_per_sec = opts['batch_size'] * num_steps / float(total_time)
    print('Avg. samples per second %.3f'%samples_per_sec)