


'''simple docstring'''


# Usage:
# ./gen-card-facebook-wmt19.py

import os
from pathlib import Path


def 		_lowercase (SCREAMING_SNAKE_CASE       ,					SCREAMING_SNAKE_CASE       ,					SCREAMING_SNAKE_CASE							):




     '''simple docstring'''





     __A	:       str      =							{
         "en": "Machine learning is great, isn\'t it?",
         "ru": "Машинное обучение - это здорово, не так ли?",
         "de": "Maschinelles Lernen ist großartig, oder?",
     }

     # BLUE scores as follows:
     # "pair": [fairseq, transformers]
     __A	:       int      =							{
         "ru-en": ["[41.3](http://matrix.statmt.org/matrix/output/1907?run_id=6937)", "39.20"],
         "en-ru": ["[36.4](http://matrix.statmt.org/matrix/output/1914?run_id=6724)", "33.47"],
         "en-de": ["[43.1](http://matrix.statmt.org/matrix/output/1909?run_id=6862)", "42.83"],
         "de-en": ["[42.3](http://matrix.statmt.org/matrix/output/1902?run_id=6750)", "41.35"],
     }
     __A	:       Tuple      =							f"{src_lang}-{tgt_lang}"

     __A	:       List[str]      =							f"\n---\nlanguage: \n- {src_lang}\n- {tgt_lang}\nthumbnail:\ntags:\n- translation\n- wmt19\n- facebook\nlicense: apache-2.0\ndatasets:\n- wmt19\nmetrics:\n- bleu\n---\n\n# FSMT\n\n## Model description\n\nThis is a ported version of [fairseq wmt19 transformer](https://github.com/pytorch/fairseq/blob/master/examples/wmt19/README.md) for {src_lang}-{tgt_lang}.\n\nFor more details, please see, [Facebook FAIR\'s WMT19 News Translation Task Submission](https://arxiv.org/abs/1907.06616).\n\nThe abbreviation FSMT stands for FairSeqMachineTranslation\n\nAll four models are available:\n\n* [wmt19-en-ru](https://huggingface.co/facebook/wmt19-en-ru)\n* [wmt19-ru-en](https://huggingface.co/facebook/wmt19-ru-en)\n* [wmt19-en-de](https://huggingface.co/facebook/wmt19-en-de)\n* [wmt19-de-en](https://huggingface.co/facebook/wmt19-de-en)\n\n## Intended uses & limitations\n\n#### How to use\n\n```python\nfrom transformers import FSMTForConditionalGeneration, FSMTTokenizer\nmname = \"facebook/wmt19-{src_lang}-{tgt_lang}\"\ntokenizer = FSMTTokenizer.from_pretrained(mname)\nmodel = FSMTForConditionalGeneration.from_pretrained(mname)\n\ninput = \"{texts[src_lang]}\"\ninput_ids = tokenizer.encode(input, return_tensors=\"pt\")\noutputs = model.generate(input_ids)\ndecoded = tokenizer.decode(outputs[0], skip_special_tokens=True)\nprint(decoded) # {texts[tgt_lang]}\n\n```\n\n#### Limitations and bias\n\n- The original (and this ported model) doesn\'t seem to handle well inputs with repeated sub-phrases, [content gets truncated](https://discuss.huggingface.co/t/issues-with-translating-inputs-containing-repeated-phrases/981)\n\n## Training data\n\nPretrained weights were left identical to the original model released by fairseq. For more details, please, see the [paper](https://arxiv.org/abs/1907.06616).\n\n## Eval results\n\npair   | fairseq | transformers\n-------|---------|----------\n{pair}  | {scores[pair][0]} | {scores[pair][1]}\n\nThe score is slightly below the score reported by `fairseq`, since `transformers`` currently doesn\'t support:\n- model ensemble, therefore the best performing checkpoint was ported (``model4.pt``).\n- re-ranking\n\nThe score was calculated using this code:\n\n```bash\ngit clone https://github.com/huggingface/transformers\ncd transformers\nexport PAIR={pair}\nexport DATA_DIR=data/$PAIR\nexport SAVE_DIR=data/$PAIR\nexport BS=8\nexport NUM_BEAMS=15\nmkdir -p $DATA_DIR\nsacrebleu -t wmt19 -l $PAIR --echo src > $DATA_DIR/val.source\nsacrebleu -t wmt19 -l $PAIR --echo ref > $DATA_DIR/val.target\necho $PAIR\nPYTHONPATH=\"src:examples/seq2seq\" python examples/seq2seq/run_eval.py facebook/wmt19-$PAIR $DATA_DIR/val.source $SAVE_DIR/test_translations.txt --reference_path $DATA_DIR/val.target --score_path $SAVE_DIR/test_bleu.json --bs $BS --task translation --num_beams $NUM_BEAMS\n```\nnote: fairseq reports using a beam of 50, so you should get a slightly higher score if re-run with `--num_beams 50`.\n\n## Data Sources\n\n- [training, etc.](http://www.statmt.org/wmt19/)\n- [test set](http://matrix.statmt.org/test_sets/newstest2019.tgz?1556572561)\n\n\n### BibTeX entry and citation info\n\n```bibtex\n@inproceedings{{...,\n  year={{2020}},\n  title={{Facebook FAIR\'s WMT19 News Translation Task Submission}},\n  author={{Ng, Nathan and Yee, Kyra and Baevski, Alexei and Ott, Myle and Auli, Michael and Edunov, Sergey}},\n  booktitle={{Proc. of WMT}},\n}}\n```\n\n\n## TODO\n\n- port model ensemble (fairseq uses 4 model checkpoints)\n\n"
     os.makedirs(UpperCamelCase_       ,					exist_ok=UpperCamelCase_							)
     __A	:       Optional[int]      =							os.path.join(UpperCamelCase_       ,					"README.md"							)
     print(f"Generating {path}"							)
     with open(UpperCamelCase_       ,					"w"       ,					encoding="utf-8"							) as f:
          f.write(UpperCamelCase_							)


# make sure we are under the root of the project
_UpperCamelCase 							=  Path(__file__).resolve().parent.parent.parent
_UpperCamelCase 							=  repo_dir / "model_cards"

for model_name in ["wmt19-ru-en", "wmt19-en-ru", "wmt19-en-de", "wmt19-de-en"]:
      _UpperCamelCase 							=  model_name.split("""-""")
      _UpperCamelCase 							=  model_cards_dir / "facebook" / model_name
      write_model_card(model_card_dir, src_lang=src_lang, tgt_lang=tgt_lang)





import argparse
import os

import gluonnlp as nlp
import mxnet as mx
import numpy as np
import torch
from gluonnlp.base import get_home_dir
from gluonnlp.model.bert import BERTEncoder
from gluonnlp.model.utils import _load_vocab
from gluonnlp.vocab import Vocab
from packaging import version
from torch import nn

from transformers import BertConfig, BertForMaskedLM, BertModel, RobertaTokenizer
from transformers.models.bert.modeling_bert import (
    BertIntermediate,
    BertLayer,
    BertOutput,
    BertSelfAttention,
    BertSelfOutput,
)
from transformers.utils import logging


if version.parse(nlp.__version__) != version.parse("0.8.3"):
 raise Exception("requires gluonnlp == 0.8.3")

if version.parse(mx.__version__) != version.parse("1.5.0"):
 raise Exception("requires mxnet == 1.5.0")

logging.set_verbosity_info()
_SCREAMING_SNAKE_CASE     :					int      =       logging.get_logger(__name__)

_SCREAMING_SNAKE_CASE     :					Any      =       "The Nymphenburg Palace is a beautiful palace in Munich!"
def      UpperCAmelCase__		(UpperCamelCase_				,UpperCamelCase_							):



     """simple docstring"""






     snake_case											=							{
         '''attention_cell''': '''multi_head''',
         '''num_layers''': 4,
         '''units''': 10_24,
         '''hidden_size''': 7_68,
         '''max_length''': 5_12,
         '''num_heads''': 8,
         '''scaled''': True,
         '''dropout''': 0.1,
         '''use_residual''': True,
         '''embed_size''': 10_24,
         '''embed_dropout''': 0.1,
         '''word_embed''': None,
         '''layer_norm_eps''': 1e-5,
         '''token_type_vocab_size''': 2,
     }

     snake_case											=							bort_4_8_768_1024_hparams

     # Let's construct the original Bort model here
     # Taken from official BERT implementation, see:
     # https://github.com/alexa/bort/blob/master/bort/bort.py
     snake_case											=							BERTEncoder(
         attention_cell=predefined_args['''attention_cell''']				,num_layers=predefined_args['''num_layers''']				,units=predefined_args['''units''']				,hidden_size=predefined_args['''hidden_size''']				,max_length=predefined_args['''max_length''']				,num_heads=predefined_args['''num_heads''']				,scaled=predefined_args['''scaled''']				,dropout=predefined_args['''dropout''']				,output_attention=UpperCamelCase_				,output_all_encodings=UpperCamelCase_				,use_residual=predefined_args['''use_residual''']				,activation=predefined_args.get('''activation'''				,'''gelu'''							)				,layer_norm_eps=predefined_args.get('''layer_norm_eps'''				,UpperCamelCase_							)				,)

     # Vocab information needs to be fetched first
     # It's the same as RoBERTa, so RobertaTokenizer can be used later
     snake_case											=							'''openwebtext_ccnews_stories_books_cased'''

     # Specify download folder to Gluonnlp's vocab
     snake_case											=							os.path.join(get_home_dir()				,'''models'''							)
     snake_case											=							_load_vocab(UpperCamelCase_				,UpperCamelCase_				,UpperCamelCase_				,cls=UpperCamelCase_							)

     snake_case											=							nlp.model.BERTModel(
         UpperCamelCase_				,len(UpperCamelCase_							)				,units=predefined_args['''units''']				,embed_size=predefined_args['''embed_size''']				,embed_dropout=predefined_args['''embed_dropout''']				,word_embed=predefined_args['''word_embed''']				,use_pooler=UpperCamelCase_				,use_token_type_embed=UpperCamelCase_				,token_type_vocab_size=predefined_args['''token_type_vocab_size''']				,use_classifier=UpperCamelCase_				,use_decoder=UpperCamelCase_				,)

     original_bort.load_parameters(UpperCamelCase_				,cast_dtype=UpperCamelCase_				,ignore_extra=UpperCamelCase_							)
     snake_case											=							original_bort._collect_params_with_prefix()

     # Build our config 🤗
     snake_case											=							{
         '''architectures''': ['''BertForMaskedLM'''],
         '''attention_probs_dropout_prob''': predefined_args['''dropout'''],
         '''hidden_act''': '''gelu''',
         '''hidden_dropout_prob''': predefined_args['''dropout'''],
         '''hidden_size''': predefined_args['''embed_size'''],
         '''initializer_range''': 0.02,
         '''intermediate_size''': predefined_args['''hidden_size'''],
         '''layer_norm_eps''': predefined_args['''layer_norm_eps'''],
         '''max_position_embeddings''': predefined_args['''max_length'''],
         '''model_type''': '''bort''',
         '''num_attention_heads''': predefined_args['''num_heads'''],
         '''num_hidden_layers''': predefined_args['''num_layers'''],
         '''pad_token_id''': 1,  # 2 = BERT, 1 = RoBERTa
         '''type_vocab_size''': 1,  # 2 = BERT, 1 = RoBERTa
         '''vocab_size''': len(UpperCamelCase_							),
     }

     snake_case											=							BertConfig.from_dict(UpperCamelCase_							)
     snake_case											=							BertForMaskedLM(UpperCamelCase_							)
     hf_bort_model.eval()

     # Parameter mapping table (Gluonnlp to Transformers)
     # * denotes layer index
     #
     # | Gluon Parameter                                                | Transformers Parameter
     # | -------------------------------------------------------------- | ----------------------
     # | `encoder.layer_norm.beta`                                      | `bert.embeddings.LayerNorm.bias`
     # | `encoder.layer_norm.gamma`                                     | `bert.embeddings.LayerNorm.weight`
     # | `encoder.position_weight`                                      | `bert.embeddings.position_embeddings.weight`
     # | `word_embed.0.weight`                                          | `bert.embeddings.word_embeddings.weight`
     # | `encoder.transformer_cells.*.attention_cell.proj_key.bias`     | `bert.encoder.layer.*.attention.self.key.bias`
     # | `encoder.transformer_cells.*.attention_cell.proj_key.weight`   | `bert.encoder.layer.*.attention.self.key.weight`
     # | `encoder.transformer_cells.*.attention_cell.proj_query.bias`   | `bert.encoder.layer.*.attention.self.query.bias`
     # | `encoder.transformer_cells.*.attention_cell.proj_query.weight` | `bert.encoder.layer.*.attention.self.query.weight`
     # | `encoder.transformer_cells.*.attention_cell.proj_value.bias`   | `bert.encoder.layer.*.attention.self.value.bias`
     # | `encoder.transformer_cells.*.attention_cell.proj_value.weight` | `bert.encoder.layer.*.attention.self.value.weight`
     # | `encoder.transformer_cells.*.ffn.ffn_2.bias`                   | `bert.encoder.layer.*.attention.output.dense.bias`
     # | `encoder.transformer_cells.*.ffn.ffn_2.weight`                 | `bert.encoder.layer.*.attention.output.dense.weight`
     # | `encoder.transformer_cells.*.layer_norm.beta`                  | `bert.encoder.layer.*.attention.output.LayerNorm.bias`
     # | `encoder.transformer_cells.*.layer_norm.gamma`                 | `bert.encoder.layer.*.attention.output.LayerNorm.weight`
     # | `encoder.transformer_cells.*.ffn.ffn_1.bias`                   | `bert.encoder.layer.*.intermediate.dense.bias`
     # | `encoder.transformer_cells.*.ffn.ffn_1.weight`                 | `bert.encoder.layer.*.intermediate.dense.weight`
     # | `encoder.transformer_cells.*.ffn.layer_norm.beta`              | `bert.encoder.layer.*.output.LayerNorm.bias`
     # | `encoder.transformer_cells.*.ffn.layer_norm.gamma`             | `bert.encoder.layer.*.output.LayerNorm.weight`
     # | `encoder.transformer_cells.*.proj.bias`                        | `bert.encoder.layer.*.output.dense.bias`
     # | `encoder.transformer_cells.*.proj.weight`                      | `bert.encoder.layer.*.output.dense.weight`

     # Helper function to convert MXNET Arrays to PyTorch
     def to_torch(UpperCamelCase_							) -> nn.Parameter:
          return nn.Parameter(torch.FloatTensor(mx_array.data().asnumpy()							)							)

     # Check param shapes and map new HF param back
     def check_and_map_params(UpperCamelCase_				,UpperCamelCase_							):
          snake_case											=							hf_param.shape

          snake_case											=							to_torch(params[gluon_param]							)
          snake_case											=							gluon_param.shape

          assert (
              shape_hf == shape_gluon
          ), F'''The gluon parameter {gluon_param} has shape {shape_gluon}, but expects shape {shape_hf} for Transformers'''

          return gluon_param

     snake_case											=							check_and_map_params(
         hf_bort_model.bert.embeddings.word_embeddings.weight				,'''word_embed.0.weight'''							)
     snake_case											=							check_and_map_params(
         hf_bort_model.bert.embeddings.position_embeddings.weight				,'''encoder.position_weight'''							)
     snake_case											=							check_and_map_params(
         hf_bort_model.bert.embeddings.LayerNorm.bias				,'''encoder.layer_norm.beta'''							)
     snake_case											=							check_and_map_params(
         hf_bort_model.bert.embeddings.LayerNorm.weight				,'''encoder.layer_norm.gamma'''							)

     # Inspired by RoBERTa conversion script, we just zero them out (Bort does not use them)
     snake_case											=							torch.zeros_like(
         hf_bort_model.bert.embeddings.token_type_embeddings.weight.data							)

     for i in range(hf_bort_config.num_hidden_layers							):
          snake_case											=							hf_bort_model.bert.encoder.layer[i]

          # self attention
          snake_case											=							layer.attention.self

          snake_case											=							check_and_map_params(
              self_attn.key.bias.data				,F'''encoder.transformer_cells.{i}.attention_cell.proj_key.bias'''							)

          snake_case											=							check_and_map_params(
              self_attn.key.weight.data				,F'''encoder.transformer_cells.{i}.attention_cell.proj_key.weight'''							)
          snake_case											=							check_and_map_params(
              self_attn.query.bias.data				,F'''encoder.transformer_cells.{i}.attention_cell.proj_query.bias'''							)
          snake_case											=							check_and_map_params(
              self_attn.query.weight.data				,F'''encoder.transformer_cells.{i}.attention_cell.proj_query.weight'''							)
          snake_case											=							check_and_map_params(
              self_attn.value.bias.data				,F'''encoder.transformer_cells.{i}.attention_cell.proj_value.bias'''							)
          snake_case											=							check_and_map_params(
              self_attn.value.weight.data				,F'''encoder.transformer_cells.{i}.attention_cell.proj_value.weight'''							)

          # self attention output
          snake_case											=							layer.attention.output

          snake_case											=							check_and_map_params(
              self_output.dense.bias				,F'''encoder.transformer_cells.{i}.proj.bias'''							)
          snake_case											=							check_and_map_params(
              self_output.dense.weight				,F'''encoder.transformer_cells.{i}.proj.weight'''							)
          snake_case											=							check_and_map_params(
              self_output.LayerNorm.bias				,F'''encoder.transformer_cells.{i}.layer_norm.beta'''							)
          snake_case											=							check_and_map_params(
              self_output.LayerNorm.weight				,F'''encoder.transformer_cells.{i}.layer_norm.gamma'''							)

          # intermediate
          snake_case											=							layer.intermediate

          snake_case											=							check_and_map_params(
              intermediate.dense.bias				,F'''encoder.transformer_cells.{i}.ffn.ffn_1.bias'''							)
          snake_case											=							check_and_map_params(
              intermediate.dense.weight				,F'''encoder.transformer_cells.{i}.ffn.ffn_1.weight'''							)

          # output
          snake_case											=							layer.output

          snake_case											=							check_and_map_params(
              bert_output.dense.bias				,F'''encoder.transformer_cells.{i}.ffn.ffn_2.bias'''							)
          snake_case											=							check_and_map_params(
              bert_output.dense.weight				,F'''encoder.transformer_cells.{i}.ffn.ffn_2.weight'''							)
          snake_case											=							check_and_map_params(
              bert_output.LayerNorm.bias				,F'''encoder.transformer_cells.{i}.ffn.layer_norm.beta'''							)
          snake_case											=							check_and_map_params(
              bert_output.LayerNorm.weight				,F'''encoder.transformer_cells.{i}.ffn.layer_norm.gamma'''							)

     # Save space and energy 🎄
     hf_bort_model.half()

     # Compare output of both models
     snake_case											=							RobertaTokenizer.from_pretrained('''roberta-base'''							)

     snake_case											=							tokenizer.encode_plus(UpperCamelCase_							)['''input_ids''']

     # Get gluon output
     snake_case											=							mx.nd.array([input_ids]							)
     snake_case											=							original_bort(inputs=UpperCamelCase_				,token_types=[]							)

     # Get Transformer output (save and reload model again)
     hf_bort_model.save_pretrained(UpperCamelCase_							)
     snake_case											=							BertModel.from_pretrained(UpperCamelCase_							)
     hf_bort_model.eval()

     snake_case											=							tokenizer.encode_plus(UpperCamelCase_				,return_tensors='''pt'''							)
     snake_case											=							hf_bort_model(**UpperCamelCase_							)[0]

     snake_case											=							output_gluon[0].asnumpy()
     snake_case											=							output_hf[0].detach().numpy()

     snake_case											=							np.max(np.abs(hf_layer - gluon_layer							)							).item()
     snake_case											=							np.allclose(UpperCamelCase_				,UpperCamelCase_				,atol=1e-3							)

     if success:
          print('''✔️ Both model do output the same tensors'''							)
     else:
          print('''❌ Both model do **NOT** output the same tensors'''							)
          print('''Absolute difference is:'''				,UpperCamelCase_							)


if __name__ == "__main__":
 _SCREAMING_SNAKE_CASE     :					List[Any]      =       argparse.ArgumentParser()
 # Required parameters
 parser.add_argument(
     "--bort_checkpoint_path", default=None, type=str, required=True, help="Path the official Bort params file."
 )
 parser.add_argument(
     "--pytorch_dump_folder_path", default=None, type=str, required=True, help="Path to the output PyTorch model."
 )
 _SCREAMING_SNAKE_CASE     :					Optional[int]      =       parser.parse_args()
 convert_bort_checkpoint_to_pytorch(args.bort_checkpoint_path, args.pytorch_dump_folder_path)




