Alternative approach
Author: amyeroberts
Pull request: yes

# What does this PR do?


Alternative way to use stop words for generated sequences. Note - it doesn't 

<details>
  <summary>Script</summary>

```py
import time
import numpy as np
from transformers.generation.stopping_criteria import StopStringCriteria, StopStringCriteria2
from transformers import AutoTokenizer

model_id = "google-bert/bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_id)

stopping_criteria = StopStringCriteria(stop_strings=["giraffe", "polo"], tokenizer=tokenizer)
long_sentence = "This is a long sentence which should eventually stop because I have the word giraffe. This is a generated sentence"
input_ids = tokenizer(long_sentence, return_tensors="pt").input_ids

# Let's iterate over input_ids, increasing the length of the input sequence at each iteration and see when the
# criterion is met
print("Current implementation")
for i in range(1, len(input_ids[0]) + 1):
    input_seq = input_ids[:, :i]
    is_done = stopping_criteria(input_ids=input_ids[:, :i], scores=None)
    print(f"Current length: {i}, stops: {is_done}, input sequence: {tokenizer.batch_decode(input_seq)}")

N_RUNS = 100

times = []
for _ in range(N_RUNS):
    start = time.time()
    for i in range(1, len(input_ids[0]) + 1):
        input_seq = input_ids[:, :i]
        is_done = stopping_criteria(input_ids=input_ids[:, :i], scores=None)
    end = time.time()
    times.append(end - start)
print(f"Average time taken - current: {np.mean(times)}, std: {np.std(times)}")

print("\nAlternative implementation")
stopping_criteria_2 = StopStringCriteria2(stop_strings=["giraffe", "polo"], tokenizer=tokenizer)
for i in range(1, len(input_ids[0]) + 1):
    input_seq = input_ids[:, :i]
    is_done = stopping_criteria_2(input_ids=input_ids[:, :i], scores=None)
    print(f"Current length: {i}, stops: {is_done}, input sequence: {tokenizer.batch_decode(input_seq)}")

times = []
for _ in range(N_RUNS):
    start = time.time()
    for i in range(1, len(input_ids[0]) + 1):
        input_seq = input_ids[:, :i]
        is_done = stopping_criteria_2(input_ids=input_ids[:, :i], scores=None)
    end = time.time()
    times.append(end - start)
print(f"Average time taken - new:     {np.mean(times)}, std: {np.std(times)}")
```
</details>

Not sure if testing assumption is correct i.e. how the input ids are passed in. When testing this alternative and the current implementation, the original `StopStringCriteria` does not stop when "giraffe" is in the sentence. 

This alternative is also faster on this small test.

Note: the alternative will stop when any of the generated strings has a stop word (which AFAICT is the same for the current `StopStringCriteria` too)

<details>
  <summary>Output</summary>

```
Current implementation
Current length: 1, stops: False, input sequence: ['[CLS]']
Current length: 2, stops: False, input sequence: ['[CLS] this']
Current length: 3, stops: False, input sequence: ['[CLS] this is']
Current length: 4, stops: False, input sequence: ['[CLS] this is a']
Current length: 5, stops: False, input sequence: ['[CLS] this is a long']
Current length: 6, stops: False, input sequence: ['[CLS] this is a long sentence']
Current length: 7, stops: False, input sequence: ['[CLS] this is a long sentence which']
Current length: 8, stops: False, input sequence: ['[CLS] this is a long sentence which should']
Current length: 9, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually']
Current length: 10, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop']
Current length: 11, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because']
Current length: 12, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i']
Current length: 13, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have']
Current length: 14, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the']
Current length: 15, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word']
Current length: 16, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word gi']
Current length: 17, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraf']
Current length: 18, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe']
Current length: 19, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe.']
Current length: 20, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe. this']
Current length: 21, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe. this is']
Current length: 22, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe. this is a']
Current length: 23, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe. this is a generated']
Current length: 24, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe. this is a generated sentence']
Current length: 25, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe. this is a generated sentence [SEP]']
Average time taken - current: 0.007625923156738281, std: 0.00019846132464233505

Alternative implementation
Current length: 1, stops: False, input sequence: ['[CLS]']
Current length: 2, stops: False, input sequence: ['[CLS] this']
Current length: 3, stops: False, input sequence: ['[CLS] this is']
Current length: 4, stops: False, input sequence: ['[CLS] this is a']
Current length: 5, stops: False, input sequence: ['[CLS] this is a long']
Current length: 6, stops: False, input sequence: ['[CLS] this is a long sentence']
Current length: 7, stops: False, input sequence: ['[CLS] this is a long sentence which']
Current length: 8, stops: False, input sequence: ['[CLS] this is a long sentence which should']
Current length: 9, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually']
Current length: 10, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop']
Current length: 11, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because']
Current length: 12, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i']
Current length: 13, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have']
Current length: 14, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the']
Current length: 15, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word']
Current length: 16, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word gi']
Current length: 17, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraf']
Current length: 18, stops: True, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe']
Current length: 19, stops: True, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe.']
Current length: 20, stops: True, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe. this']
Current length: 21, stops: True, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe. this is']
Current length: 22, stops: True, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe. this is a']
Current length: 23, stops: True, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe. this is a generated']
Current length: 24, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe. this is a generated sentence']
Current length: 25, stops: False, input sequence: ['[CLS] this is a long sentence which should eventually stop because i have the word giraffe. this is a generated sentence [SEP]']
Average time taken - new:     0.0011045789718627929, std: 2.974982062175288e-05
```
</details>


Comments:
cc @Rocketknight1 

The docs for this PR live [here](https://moon-ci-docs.huggingface.co/docs/transformers/pr_29152). All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.