Constrained beam search in chat
Author: esaks1
Pull request: no
Labels: name: Generation

### System Info

- `transformers` version: 4.37.2
- Platform: Linux-6.5.0-27-generic-x86_64-with-glibc2.35
- Python version: 3.11.8
- Huggingface_hub version: 0.20.3
- Safetensors version: 0.4.2
- Accelerate version: 0.28.0
- Accelerate config:    not found
- PyTorch version (GPU?): 2.2.2+cu118 (True)
- Tensorflow version (GPU?): not installed (NA)
- Flax version (CPU?/GPU?/TPU?): not installed (NA)
- Jax version: not installed
- JaxLib version: not installed
- Using GPU in script?: Yes
- Using distributed or parallel set-up in script?: no...?

### Who can help?

@gante

### Information

- [ ] The official example scripts
- [ ] My own modified scripts

### Tasks

- [ ] An officially supported task in the `examples` folder (such as GLUE/SQuAD, ...)
- [ ] My own task or dataset (give details below)

### Reproduction

```python3
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch

TOKEN="my_hf_token" # CHANGE
MODEL_NAME = "meta-llama/Llama-2-13b-chat-hf"

model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME, device_map="auto", load_in_4bit=True, token=TOKEN,      torch_dtype=torch.float16, bnb_4bit_compute_dtype=torch.float16)

tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME,token=TOKEN)
tokenizer.use_default_system_prompt=False


# test conversation
conversation = []
conversation.append({"role": "system", "content": "The following is dialogue at a coffee chop. You are the barista. The customer is ordering a coffee."})
user_input = "What a lovely morning! I would like a coffee please, although that cake looks delicious too."
conversation.append({"role": "user", "content": user_input})

#at least one of these words should be generated
forced_words = ["please", "delicious"]
forced_ids = [tokenizer(forced_words, add_special_tokens=False).input_ids]

input_ids = tokenizer.apply_chat_template(conversation, return_tensors="pt").to("cuda:0")

input_length = input_ids.shape[1]

res = model.generate(
    input_ids, 
    max_new_tokens=50, 
    force_words_ids=forced_ids, 
    num_beams = 10,
    num_return_sequences=1,
)

res_decoded = tokenizer.decode(res[0], skip_special_tokens=True)
print("Full output:\n", res_decoded)

bot_response = tokenizer.batch_decode(res[:, input_length:], skip_special_tokens=True)[0]
print("\nBot response:\n", bot_response)

```

### Expected behavior

Although I would not necessarily call this a bug, I would want one of the words "please" and "delicious" to be generated but, since they are present in the conversation history, they are not. 

This was the response I got: 
```txt
Good morning! It certainly is a lovely day today. I'd be happy to get you a cup of coffee. Would you like a latte, cappuccino, or perhaps a drip coffee? And would you like
```

I have tried getting around this by writing my own version of the DisjunctiveConstraint class in src/transformers/generation/beam_constraints.py and using the constraints argument in the generation with no luck. 

Considering this may not be a prioritized issue I would highly appreciate any suggestions or pointers on how I can make the forced words work in a chat setting myself

Comments:
I have not tested it enough to trust that it is a safe solution but what I ended up doing to fix this issue was to go to beam_search.py and slice the token_ids list in all calls to reset(), so that it does not include the prompt.

Hi @esaks1 👋 Thank you for opening this issue!

Constrained generation is indeed not being actively maintained due to lack of bandwidth -- it deserves a proper dive at some point in the future.

Meanwhile, I'd like to suggest the following workarounds:
1. If your constraints are structured, i.e. you know the shape of your desired LLM output, have a look at this library: https://github.com/outlines-dev/outlines
2. If you simply want to fit certain words in the answer, you may consider passing `sequence_bias` to make those words more likely. If they become too repetitive with `sequence_bias`, you should be able to avoid repetitions with `repetition_penalty` ([full docs](https://huggingface.co/docs/transformers/main/en/main_classes/text_generation#transformers.GenerationConfig))

This issue has been automatically marked as stale because it has not had recent activity. If you think this still needs to be addressed please comment on this thread.

Please note that issues that do not follow the [contributing guidelines](https://github.com/huggingface/transformers/blob/main/CONTRIBUTING.md) are likely to be ignored.