### Description

When completing a zero_shot classification task, there is the input sequence (provided by the user), and labels (also provided by the user). 

Tokenization as it is done now tokenizes the input sequence len(labels) times. We should really only do it once and pass those tokenized values to request builder. 

Some of the changes introduce here: https://github.com/elastic/elasticsearch/pull/84777 should make implementing this simpler (as there will be a unified temporary tokenization result object).
x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/nlp/tokenizers/BertTokenizer.java
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
 * Performs basic tokenization and normalization of input text
 * then tokenizes with the WordPiece algorithm using the given
 * vocabulary.
 * <p>
 * Derived from
 * https://github.com/huggingface/transformers/blob/ba8c4d0ac04acfcdbdeaed954f698d6d5ec3e532/src/transformers/tokenization_bert.py
 */
public class BertTokenizer extends NlpTokenizer {
    public static final String UNKNOWN_TOKEN = "[UNK]";
    public static final String SEPARATOR_TOKEN = "[SEP]";
    public static final String PAD_TOKEN = "[PAD]";
    public static final String CLASS_TOKEN = "[CLS]";
    public static final String MASK_TOKEN = "[MASK]";
    private static final Set<String> NEVER_SPLIT = Set.of(MASK_TOKEN);
    private final WordPieceAnalyzer wordPieceAnalyzer;
    protected final List<String> originalVocab;
    
    private final SortedMap<String, Integer> vocab;
    protected final boolean withSpecialTokens;
    private final int maxSequenceLength;
    protected final int sepTokenId;
    private final int clsTokenId;
    private final String padToken;
    protected final int padTokenId;
    private final String maskToken;
    private final String unknownToken;
    protected BertTokenizer(