def main():
    """Main function."""
    time_start = time.time()
    logging.info('loading vocab file from dataset: %s', args.vocab)
    vocab_obj = nlp.data.utils._load_pretrained_vocab(args.vocab)
    tokenizer = BERTTokenizer(
        vocab=vocab_obj, lower='uncased' in args.vocab)

    input_files = []
    for input_pattern in args.input_file.split(','):
        input_files.extend(glob.glob(os.path.expanduser(input_pattern)))

    logging.info('*** Reading from %d input files ***', len(input_files))
    for input_file in input_files:
        logging.info('  %s', input_file)

    num_outputs = min(args.num_outputs, len(input_files))

    output_dir = os.path.expanduser(args.output_dir)
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    rng = random.Random(args.random_seed)
    nworker = args.num_workers

    # calculate the number of splits
    file_splits = []
    split_size = (len(input_files) + num_outputs - 1) // num_outputs
    for i in range(num_outputs - 1):
        file_splits.append(input_files[i*split_size:(i+1)*split_size])
    file_splits.append(input_files[(num_outputs-1)*split_size:])

    # prepare workload
    suffix = 'npz' if args.format == 'numpy' else 'rec'
    count = 0
    map_args = []
    pool_args = (tokenizer, args.max_seq_length, args.dupe_factor,\
                 args.short_seq_prob, args.masked_lm_prob,
                 args.max_predictions_per_seq, rng)
    for i, file_split in enumerate(file_splits):
        out = os.path.join(output_dir, 'part-{}.{}'.format(str(i).zfill(3), suffix))
        count += len(file_split)
        map_args.append((file_split, out) + pool_args)

    # sanity check
    assert count == len(input_files)

    # dispatch to workers
    if nworker > 1:
        pool = Pool(nworker)
        pool.map(create_training_instances, map_args)
    else:
        for map_arg in map_args:
            create_training_instances(map_arg)

    time_end = time.time()
    logging.info('Time cost=%.1f', time_end - time_start)
Main function.