def template_to_ids(template, config, tokenizer, max_seq_length):
  """Converts template to a list of input ids and its corresponding mask."""
  template_shards = template.split(" <piece> ")
  input_ids = []
  # input mask will be applied during the discrete optimization, only unmasked
  # tokens will get optimized.
  input_mask = []
  # bert_input_mask will be applied during self-attention, it is mainly applied
  # to PADDING tokens.
  bert_input_mask = []
  # token_type_ids are needed for pairwise classification tasks like MNLI.
  token_type_ids = []
  current_index = 0
  current_token_type = 0

  for shard in template_shards:
    # Precautionary measure to prevent errors for templates > max_seq_length
    if current_index > max_seq_length:
      break

    shard_token, shard_quantity, opt_from_embedding = parse_shard(
        shard=shard, current_index=current_index, max_seq_length=max_seq_length)

    update_bert_input_mask(
        shard_token=shard_token,
        shard_quantity=shard_quantity,
        tokenizer=tokenizer,
        bert_input_mask=bert_input_mask)

    current_token_type = update_token_type_ids(
        shard_token=shard_token,
        shard_quantity=shard_quantity,
        tokenizer=tokenizer,
        token_type_ids=token_type_ids,
        current_token_type=current_token_type)

    if shard_token == "[EMPTY]":
      # Fill in each of the [EMPTY] slots with random words from vocabulary
      input_ids.extend([
          random.randint(0, config.vocab_size - 1)
          for _ in range(shard_quantity)
      ])
      input_mask.extend([1 for _ in range(shard_quantity)])
      current_index += shard_quantity
    else:
      if shard_token in tokenizer.vocab:
        token_ids = [tokenizer.vocab[shard_token]]
      else:
        token_ids = tokenizer.convert_tokens_to_ids(
            tokenizer.tokenize(shard_token))
      # repeat sequence of tokens according to number of shards
      for _ in range(shard_quantity):
        input_ids.extend(token_ids)
        if opt_from_embedding:
          # Since opt_from_embedding is true, the user wants the input to be
          # used as a starting point to optimize the words
          input_mask.extend([1 for _ in token_ids])
        else:
          # These tokens are fixed, so we use 0 in their positions in the mask
          input_mask.extend([0 for _ in token_ids])
        # Move the index forward by the number of tokens done
        current_index += len(token_ids)

  return (np.array(input_ids), np.array(input_mask), np.array(bert_input_mask),
          np.array(token_type_ids))
Converts template to a list of input ids and its corresponding mask.
language/bert_extraction/steal_bert_classifier/embedding_perturbations/embedding_util.py