Tokenizer wrongly splits the drug SMILES
Author: Chris-Tang6
Pull request: no

### System Info

- `transformers` version: 4.33.0
- Platform: Linux-5.15.133+-x86_64-with-glibc2.31
- Python version: 3.10.12
- Huggingface_hub version: 0.16.4
- Safetensors version: 0.3.3
- Accelerate version: 0.22.0
- Accelerate config: 	not found
- PyTorch version (GPU?): 2.0.0+cpu (False)
- Tensorflow version (GPU?): 2.12.0 (False)
- Flax version (CPU?/GPU?/TPU?): 0.7.2 (cpu)
- Jax version: 0.4.13
- JaxLib version: 0.4.13
- Using GPU in script?: <fill in>
- Using distributed or parallel set-up in script?: <fill in>

### Who can help?

@ArthurZucker Hello Arthur😊  I have a problem when I use ChemBerta to get pretrained Drug feature. One step is to use Tokenizer to split the drug SMILES to single atoms. And I found the splited atoms are not match with the original seq.

e.g. The Iuput seq is ```COC1=C(C=C2C(=C1)CCN=C2C3=CC(=C(C=C3)Cl)Cl)Cl```
However the output of tokenizer incorrectly labeled the 'Cl' as 'C', I don't konw how the fix it. And I also found that in the ChenBERTa token table, it indeed has the 'Cl' token.
![image](https://github.com/huggingface/transformers/assets/53926670/9877917a-a426-4901-8686-703dffb34853)

The output of the tokenize() result as follow:
```['C', 'O', 'C', '1', '=', 'C', '(', 'C', '=', 'C', '2', 'C', '(', '=', 'C', '1', ')', 'C', 'C', 'N', '=', 'C', '2', 'C', '3', '=', 'C', 'C', '(', '=', 'C', '(', 'C', '=', 'C', '3', ')', 'C', ')', 'C', ')', 'C']```


### Information

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

### Tasks

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

### Reproduction

Code as below:
```
from IPython.display import clear_output as clr
import numpy as np
import pandas as pd
import torch
from tqdm import tqdm
from transformers import AutoModelForMaskedLM, AutoTokenizer
import torch.nn as nn

model_name = "DeepChem/ChemBERTa-77M-MLM" 
chemberta = AutoModelForMaskedLM.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)
print(chemberta)
chemberta._modules["lm_head"] = nn.Identity()
chemberta.eval()

seq = 'COC1=C(C=C2C(=C1)CCN=C2C3=CC(=C(C=C3)Cl)Cl)Cl'
encoded_input = tokenizer(seq, return_tensors="pt", padding=False, truncation=True, add_special_tokens=False)
encoded_token = tokenizer.tokenize(seq)
model_output = chemberta(**encoded_input)

print(len(seq), seq)
print(encoded_input.input_ids)
print(len(encoded_token), encoded_token)
print(model_output)
```

### Expected behavior

I hope to split the SMILES seq coorectly.

Comments:
Hi @Chris-Tang6, thanks for raising this issue! 

I'm not a chemist myself, so want to make sure I've understood the desired behaviour. Could you provide what you would have expected the tokenized sequence to be? Should this also apply to `C0`, `C2` and `C3` as well as `C1`? 

I'm not sure what `vocab_sub2num` is in the provided example. However, if I load the tokenizer from the code snippet, I can see that `C1` isn't in the vocabulary. 

```
from transformers import AutoTokenizer

model_name = "DeepChem/ChemBERTa-77M-MLM" 
tokenizer = AutoTokenizer.from_pretrained(model_name)

# Prints True
print('C' in tokenizer.vocab)

# Prints False
print('C1' in tokenizer.vocab)
```

Thank you @amyeroberts 😁
In my opinion, If the 'C1' or 'C0‘ not in the token-vocab, it is acceptable to split as 'C'. I only hope to split the seqs following the token-vocab and don't have semantic errors.

Also, the `vocab_sub2num` is caculated as follow:
```
vocab_sub2num = tokenizer.vocab
vocab_num2sub = {value:key for key,value in vocab_sub2num.items()}
```


Hey! Correct me if I am wrong, but the issue is with `l` not `1`. See the following snippet:
```python 
>>> from transformers import AutoTokenizer
>>> model_name = "DeepChem/ChemBERTa-77M-MLM" 
>>> tokenizer = AutoTokenizer.from_pretrained(model_name)
>>> tokenizer.tokenize("C1")
['C', '1']
>>> tokenizer.tokenize("Cl")
['C']
```
`l` is not part of the vocab but should still be tokenized and then encoded as `[UNK]`.

A quick fix is to use the slow tokenizer. I don't really know why it doesn't work and can try to see if it's expected or not. 

```python 
>>> tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast = False)
>>> tokenizer.encode("Cl")
[12, 16, 11, 13]
```



Hi @ArthurZucker, you are right. I tried the slow tokenizer, but it still not works well.
``` python
>>> seq = 'COC1=C(C=C2C(=C1)CCN=C2C3=CC(=C(C=C3)Cl)Cl)Cl'
>>> tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast = False)
>>> tokenizer(seq, return_tensors="pt", padding=False, truncation=True)
tensor([[12, 16, 19, 16, 20, 22, 16, 17, 16, 22, 16, 21, 16, 17, 22, 16, 20, 18,
         16, 16, 23, 22, 16, 21, 16, 26, 22, 16, 16, 17, 22, 16, 17, 16, 22, 16,
         26, 18, 16, 11, 18, 16, 11, 18, 16, 11, 13]])
```

Hey, could you elaborate on what is not working well? 

Hi, I read again about the [ChemBERTa paper](https://[arxiv.org/pdf/2010.09885.pdf](https://arxiv.org/pdf/2010.09885.pdf)). It seems that the problem is not on the tokenizer.

The author compaired two tokenizer: BPE tokenizer and Smiles tokenizer(in deepchem). For the BPE can replace the rare or unknown words with konwn words. And I think the `AutoTokenizer` is same as the `BPE` that's why the 'Cl' is replaced with 'C'. 

In contrast, the Smilestokenizer can hold the rare words(e.g. `Cl`, `Mn`, `Cu`) and the result is slightly better than the BPE.
![image](https://github.com/huggingface/transformers/assets/53926670/47d604fc-dac0-49bc-acc4-4d625bf4a628)

And the usage of SmilesTokenizer as follow:
The vocab.txt from [here](https://github.com/seyonechithrananda/bert-loves-chemistry/blob/b0b29205b4db002a043152e0dd3c0d23fbd351fe/chemberta/bertviz_clone/vocab.txt#L4).
``` python
from deepchem.feat import SmilesTokenizer
vocab_path = './vocab.txt'  # path to vocab.txt
tokenizer = SmilesTokenizer(vocab_path)  # SmilesTokenizer
tokenizer.tokenize('Cl')
>>> ['Cl']
```



Note that you can also always add tokens to the vocab after training using `tokenizer.add_tokens(["Cl", "Mn"])` etc. 
You can also enable bytefallback for unkown words, adding 256 unicodes to the vocab to not lose the raw information.
Anyway glad you issue is fixed! 

Hi, thanks for the insightful discussion. My question is since the model was pretrained using the default BPE algorithm, do you think the usage of different tokenizer here is going to affect the performance? Specifically, if all 'Cl' were taken as 'C' during the training process, I assume there's be no relevant embeddings for 'Cl' without fine-tuning. Any clue?   

Exactly, if there are no embeddings for `"Cl"` you have to finetune