docs: def parse_arguments(argv):
    """Parse the command line arguments."""
    parser = DatalabParser(
        epilog=('Note that if using a DNN model, --hidden-layer-size1=NUM, '
                '--hidden-layer-size2=NUM, ..., is also required. '),
        datalab_epilog=("""
    Note that if using a DNN model,
    hidden-layer-size1: NUM
    hidden-layer-size2: NUM
    ...
    is also required. """))
  
    # HP parameters
    parser.add_argument(
        '--epsilon', type=float, default=0.0005, metavar='R',
        help='tf.train.AdamOptimizer epsilon. Only used in dnn models.')
    parser.add_argument(
        '--l1-regularization', type=float, default=0.0, metavar='R',
        help='L1 term for linear models.')
    parser.add_argument(
        '--l2-regularization', type=float, default=0.0, metavar='R',
        help='L2 term for linear models.')
  
    # Model parameters
    parser.add_argument(
      '--model', required=True,
      choices=['linear_classification', 'linear_regression', 'dnn_classification', 'dnn_regression'])
    parser.add_argument(
        '--top-n', type=int, default=0, metavar='N',
        help=('For classification problems, the output graph will contain the '
              'labels and scores for the top n classes, and results will be in the form of '
              '"predicted, predicted_2, ..., probability, probability_2, ...". '
              'If --top-n=0, then all labels and scores are returned in the form of '
              '"predicted, class_name1, class_name2,...".'))
  
    # HP parameters
    parser.add_argument(
        '--learning-rate', type=float, default=0.01, metavar='R',
        help='optimizer learning rate.')
  
    # Training input parameters
    parser.add_argument(
        '--max-steps', type=int, metavar='N',
        help='Maximum number of training steps to perform. If unspecified, will '
             'honor "max-epochs".')
    parser.add_argument(
        '--max-epochs', type=int, default=1000, metavar='N',
        help='Maximum number of training data epochs on which to train. If '
             'both "max-steps" and "max-epochs" are specified, the training '
             'job will run for "max-steps" or "num-epochs", whichever occurs '
             'first. If early stopping is enabled, training may also stop '
             'earlier.')
    parser.add_argument(
        '--train-batch-size', type=int, default=64, metavar='N',
        help='How many training examples are used per step. If num-epochs is '
             'used, the last batch may not be full.')
    parser.add_argument(
        '--eval-batch-size', type=int, default=64, metavar='N',
        help='Batch size during evaluation. Larger values increase performance '
             'but also increase peak memory usgae on the master node. One pass '
             'over the full eval set is performed per evaluation run.')
    parser.add_argument(
        '--min-eval-frequency', type=int, default=1000, metavar='N',
        help='Minimum number of training steps between evaluations. Evaluation '
             'does not occur if no new checkpoint is available, hence, this is '
             'the minimum. If 0, the evaluation will only happen after training. ')
    parser.add_argument(
        '--early-stopping-num_evals', type=int, default=3,
        help='Automatic training stop after results of specified number of evals '
             'in a row show the model performance does not improve. Set to 0 to '
             'disable early stopping.')
    parser.add_argument(
        '--logging-level', choices=['error', 'warning', 'info'],
        help='The TF logging level. If absent, use info for cloud training '
             'and warning for local training.')
  
    args, remaining_args = parser.parse_known_args(args=argv[1:])
  
    # All HP parambeters must be unique, so we need to support an unknown number
    # of --hidden-layer-size1=10 --lhidden-layer-size2=10 ...
    # Look at remaining_args for hidden-layer-size\d+ to get the layer info.
  
    # Get number of layers
    pattern = re.compile('hidden-layer-size(\d+)')
    num_layers = 0
    for other_arg in remaining_args:
      match = re.search(pattern, other_arg)
      if match:
        if int(match.group(1)) <= 0:
          raise ValueError('layer size must be a positive integer. Was given %s' % other_arg)
        num_layers = max(num_layers, int(match.group(1)))
  
    # Build a new parser so we catch unknown args and missing layer_sizes.
    parser = argparse.ArgumentParser()
    for i in range(num_layers):
      parser.add_argument('--hidden-layer-size%s' % str(i + 1), type=int, required=True)
  
    layer_args = vars(parser.parse_args(args=remaining_args))
    hidden_layer_sizes = []
    for i in range(num_layers):
      key = 'hidden_layer_size%s' % str(i + 1)
      hidden_layer_sizes.append(layer_args[key])
  
    assert len(hidden_layer_sizes) == num_layers
    args.hidden_layer_sizes = hidden_layer_sizes
  
    return args