docs: def train(*tf_records: "Records to train on"):
      """Train on examples."""
      tf.logging.set_verbosity(tf.logging.INFO)
      estimator = dual_net.get_estimator()
  
      effective_batch_size = FLAGS.train_batch_size
      if FLAGS.use_tpu:
          effective_batch_size *= FLAGS.num_tpu_cores
  
      if FLAGS.use_tpu:
          if FLAGS.use_bt:
              def _input_fn(params):
                  games = bigtable_input.GameQueue(
                      FLAGS.cbt_project, FLAGS.cbt_instance, FLAGS.cbt_table)
                  games_nr = bigtable_input.GameQueue(
                      FLAGS.cbt_project, FLAGS.cbt_instance, FLAGS.cbt_table + '-nr')
                  return preprocessing.get_tpu_bt_input_tensors(
                      games,
                      games_nr,
                      params['batch_size'],
                      number_of_games=FLAGS.window_size,
                      random_rotation=True)
          else:
              def _input_fn(params):
                  return preprocessing.get_tpu_input_tensors(
                      params['batch_size'],
                      tf_records,
                      random_rotation=True)
          # Hooks are broken with TPUestimator at the moment.
          hooks = []
      else:
          def _input_fn():
              return preprocessing.get_input_tensors(
                  FLAGS.train_batch_size,
                  tf_records,
                  filter_amount=FLAGS.filter_amount,
                  shuffle_buffer_size=FLAGS.shuffle_buffer_size,
                  random_rotation=True)
  
          hooks = [UpdateRatioSessionHook(FLAGS.work_dir),
                   EchoStepCounterHook(output_dir=FLAGS.work_dir)]
  
      steps = FLAGS.steps_to_train
      logging.info("Training, steps = %s, batch = %s -> %s examples",
                   steps or '?', effective_batch_size,
                   (steps * effective_batch_size) if steps else '?')
  
      if FLAGS.use_bt:
          games = bigtable_input.GameQueue(
              FLAGS.cbt_project, FLAGS.cbt_instance, FLAGS.cbt_table)
          if not games.read_wait_cell():
              games.require_fresh_games(20000)
          latest_game = games.latest_game_number
          index_from = max(latest_game, games.read_wait_cell())
          print("== Last game before training:", latest_game, flush=True)
          print("== Wait cell:", games.read_wait_cell(), flush=True)
  
      try:
          estimator.train(_input_fn, steps=steps, hooks=hooks)
          if FLAGS.use_bt:
              bigtable_input.set_fresh_watermark(games, index_from,
                                                 FLAGS.window_size)
      except:
          if FLAGS.use_bt:
              games.require_fresh_games(0)
          raise