Code in the documentation on fine-tuning mBART-50 for machine translation doesn't seem to perform a backward pass
Author: Franck-Dernoncourt
Pull request: no

(Assignee: @patrickvonplaten)

I try to fine-tune mBART-50 ([paper](https://arxiv.org/pdf/2008.00401), [pre-trained model on Hugging Face](https://huggingface.co/facebook/mbart-large-50)) for machine translation in the transformers Python library. To test the fine-tuning, I am trying to simply teach mBART-50 a new word that I made up (the made up French "billozarion", whose made up translation in English is "plorization").

I use the following code. Over 95% of the code is from the [Hugging Face documentation](https://huggingface.co/docs/transformers/model_doc/mbart#training-of-mbart50):


```
from transformers import MBartForConditionalGeneration, MBart50TokenizerFast

print('Model loading started')
model = MBartForConditionalGeneration.from_pretrained("facebook/mbart-large-50")
tokenizer = MBart50TokenizerFast.from_pretrained("facebook/mbart-large-50", src_lang="fr_XX", tgt_lang="en_XX")
print('Model loading done')

src_text = " billozarion "
tgt_text =  " plorization "

model_inputs = tokenizer(src_text, return_tensors="pt")
with tokenizer.as_target_tokenizer():
    labels = tokenizer(tgt_text, return_tensors="pt").input_ids

print('Fine-tuning started')
for i in range(1000):
    #pass
    model(**model_inputs, labels=labels) # forward pass
print('Fine-tuning ended')
    
# Testing whether the model learned the new word. Translate French to English
tokenizer = MBart50TokenizerFast.from_pretrained("facebook/mbart-large-50-many-to-many-mmt")
tokenizer.src_lang = "fr_XX"
article_fr = src_text
encoded_fr = tokenizer(article_fr, return_tensors="pt")
generated_tokens = model.generate(**encoded_fr, forced_bos_token_id=tokenizer.lang_code_to_id["en_XX"])
translation = tokenizer.batch_decode(generated_tokens, skip_special_tokens=True)
print(translation)
```

However, the new word wasn't learned. The output is "billozarion" instead of "plorization". 

I'm strictly following the Hugging Face documentation, unless I missed something.  The `# forward pass` does make me concerned, as one would need a backward pass to update the gradients. Maybe this means that the documentation is incorrect, however I can't test that hypothesis as I don't know how to add the backward pass. Anyway, it seems there is an issue with the documentation on fine-tuning mBART-50 for machine translation: either the comment `# forward pass` is incorrect, or the code itself is missing the backward pass.

---

Environment that I used to run the code: Ubuntu 20.04.5 LTS with an NVIDIA A100 40GB GPU (I also tested with an NVIDIA T4 Tensor Core GPU) and CUDA 12.0 with the following conda environment:

```
conda create --name mbart-python39 python=3.9
conda activate mbart-python39 
pip install transformers==4.28.1
pip install chardet==5.1.0
pip install sentencepiece==0.1.99
pip install protobuf==3.20
```

Comments:
The documentation shows how to do a forward pass of the model, it's not an example of full training. Those examples can be found in the [examples folder](https://github.com/huggingface/transformers/tree/main/examples/pytorch). You do need to define an optimizer, call `loss.backward()` etc. for a full training loop, like for any other PyTorch model.

Thanks @sgugger ! The documentation incorrectly claims it performs fine-tuning. That should be fixed, either by removing the fine-tuning claim or preferably by actually providing a fine-tuning code example. 

I'm sorry but I don't see the words fine-tuning in the link you provided. Could you point out to me where the claim is? I see a snippet of code showing how to use the model for training, which you should plugin your actual training loop with your own data.

Thanks @sgugger , good idea, I should have provided the quote. Here is the quote from the [Hugging Face documentation](https://huggingface.co/docs/transformers/model_doc/mbart#training-of-mbart50):

![image](https://user-images.githubusercontent.com/15331/236707560-6123ba1a-53e1-4f72-9853-cd2264823ff2.png)

The presence of "Training of MBart-50" and "Supervised training" heavily implies that the code trains the model.


One could add the following to fine-tune mBART-50:


```
from transformers.optimization import AdamW

# Set up the optimizer and training settings
optimizer = AdamW(model.parameters(), lr=1e-4)
model.train()

print('Fine-tuning started')
for i in range(100):
    optimizer.zero_grad()
    output = model(**model_inputs, labels=labels) # forward pass
    loss = output.loss
    loss.backward()
    optimizer.step()
print('Fine-tuning ended')
```

Full code:

```
from transformers import MBartForConditionalGeneration, MBart50TokenizerFast
from transformers.optimization import AdamW
import os
os.environ["TOKENIZERS_PARALLELISM"] = "false"


print('Model loading started')
model = MBartForConditionalGeneration.from_pretrained("facebook/mbart-large-50")
tokenizer = MBart50TokenizerFast.from_pretrained("facebook/mbart-large-50", src_lang="fr_XX", tgt_lang="en_XX")
print('Model loading done')

src_text = " billozarion "
tgt_text =  " plorizatizzzon "

model_inputs = tokenizer(src_text, return_tensors="pt")
with tokenizer.as_target_tokenizer():
    labels = tokenizer(tgt_text, return_tensors="pt").input_ids

# Set up the optimizer and training settings
optimizer = AdamW(model.parameters(), lr=1e-4)
model.train()

print('Fine-tuning started')
for i in range(100):
    optimizer.zero_grad()
    output = model(**model_inputs, labels=labels) # forward pass
    loss = output.loss
    loss.backward()
    optimizer.step()
print('Fine-tuning ended')
    
# translate French to English
tokenizer = MBart50TokenizerFast.from_pretrained("facebook/mbart-large-50-many-to-many-mmt")
tokenizer.src_lang = "fr_XX"
article_fr = src_text
encoded_fr = tokenizer(article_fr, return_tensors="pt")
generated_tokens = model.generate(**encoded_fr, forced_bos_token_id=tokenizer.lang_code_to_id["en_XX"])
translation =tokenizer.batch_decode(generated_tokens, skip_special_tokens=True)
print(translation)
```

It outputs the correct made up translation "plorizatizzzon". I'd suggest that the code in the documentation be updated accordingly to truly perform fine-tuning.

https://github.com/huggingface/transformers/tree/main/examples/pytorch/translation contains two more advanced scripts to fine-tune mBART (thanks [sgugger](https://github.com/sgugger) for [pointing](https://github.com/huggingface/transformers/issues/23185#issuecomment-1537564079) me to it).

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.