






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

import os
from pathlib import Path







def   SCREAMING_SNAKE_CASE       (				snake_case_      :							Optional[Any]  ,						snake_case_      :							Tuple  ,						snake_case_      :							Tuple     ):
	snake_case__				:   Tuple     =						{
	    "en": "Machine learning is great, isn't it?",
	    "ru": "Машинное обучение - это здорово, не так ли?",
	    "de": "Maschinelles Lernen ist großartig, oder?",
	}

	# BLUE scores as follows:
	# "pair": [fairseq, transformers]
	snake_case__				:   str     =						{
	    "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"],
	}
	snake_case__				:   Tuple     =						F'''{src_lang}-{tgt_lang}'''

	snake_case__				:   Any     =						F'''
---
language: 
- {src_lang}
- {tgt_lang}
thumbnail:
tags:
- translation
- wmt19
- facebook
license: apache-2.0
datasets:
- wmt19
metrics:
- bleu
---

# FSMT

## Model description

This is a ported version of [fairseq wmt19 transformer](https://github.com/pytorch/fairseq/blob/master/examples/wmt19/README.md) for {src_lang}-{tgt_lang}.

For more details, please see, [Facebook FAIR\'s WMT19 News Translation Task Submission](https://arxiv.org/abs/1907.06616).

The abbreviation FSMT stands for FairSeqMachineTranslation

All four models are available:

* [wmt19-en-ru](https://huggingface.co/facebook/wmt19-en-ru)
* [wmt19-ru-en](https://huggingface.co/facebook/wmt19-ru-en)
* [wmt19-en-de](https://huggingface.co/facebook/wmt19-en-de)
* [wmt19-de-en](https://huggingface.co/facebook/wmt19-de-en)

## Intended uses & limitations

#### How to use

```python
from transformers import FSMTForConditionalGeneration, FSMTTokenizer
mname = "facebook/wmt19-{src_lang}-{tgt_lang}"
tokenizer = FSMTTokenizer.from_pretrained(mname)
model = FSMTForConditionalGeneration.from_pretrained(mname)

input = "{texts[src_lang]}"
input_ids = tokenizer.encode(input, return_tensors="pt")
outputs = model.generate(input_ids)
decoded = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(decoded) # {texts[tgt_lang]}

```

#### Limitations and bias

- 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)

## Training data

Pretrained weights were left identical to the original model released by fairseq. For more details, please, see the [paper](https://arxiv.org/abs/1907.06616).

## Eval results

pair   | fairseq | transformers
-------|---------|----------
{pair}  | {scores[pair][0]} | {scores[pair][1]}

The score is slightly below the score reported by `fairseq`, since `transformers`` currently doesn\'t support:
- model ensemble, therefore the best performing checkpoint was ported (``model4.pt``).
- re-ranking

The score was calculated using this code:

```bash
git clone https://github.com/huggingface/transformers
cd transformers
export PAIR={pair}
export DATA_DIR=data/$PAIR
export SAVE_DIR=data/$PAIR
export BS=8
export NUM_BEAMS=15
mkdir -p $DATA_DIR
sacrebleu -t wmt19 -l $PAIR --echo src > $DATA_DIR/val.source
sacrebleu -t wmt19 -l $PAIR --echo ref > $DATA_DIR/val.target
echo $PAIR
PYTHONPATH="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
```
note: fairseq reports using a beam of 50, so you should get a slightly higher score if re-run with `--num_beams 50`.

## Data Sources

- [training, etc.](http://www.statmt.org/wmt19/)
- [test set](http://matrix.statmt.org/test_sets/newstest2019.tgz?1556572561)


### BibTeX entry and citation info

```bibtex
@inproceedings{{...,
  year={{2020}},
  title={{Facebook FAIR\'s WMT19 News Translation Task Submission}},
  author={{Ng, Nathan and Yee, Kyra and Baevski, Alexei and Ott, Myle and Auli, Michael and Edunov, Sergey}},
  booktitle={{Proc. of WMT}},
}}
```


## TODO

- port model ensemble (fairseq uses 4 model checkpoints)

'''
	os.makedirs(snake_case_  ,						exist_ok=snake_case_     )
	snake_case__				:   Any     =						os.path.join(snake_case_  ,						"README.md"     )
	print(F'''Generating {path}'''     )
	with open(snake_case_  ,						"w"  ,						encoding="utf-8"     ) as f:
		f.write(snake_case_     )


# make sure we are under the root of the project
__lowerCamelCase      :    Optional[int]   		=   Path(__file__).resolve().parent.parent.parent
__lowerCamelCase      :    List[Any]   		=   repo_dir / """model_cards"""

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











import argparse

import fairseq
import torch

from transformers import UniSpeechSatConfig, UniSpeechSatForCTC, UniSpeechSatForPreTraining, logging


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

__lowerCamelCase      :    int   		=   {
    """post_extract_proj""": """feature_projection.projection""",
    """encoder.pos_conv.0""": """encoder.pos_conv_embed.conv""",
    """self_attn.k_proj""": """encoder.layers.*.attention.k_proj""",
    """self_attn.v_proj""": """encoder.layers.*.attention.v_proj""",
    """self_attn.q_proj""": """encoder.layers.*.attention.q_proj""",
    """self_attn.out_proj""": """encoder.layers.*.attention.out_proj""",
    """self_attn_layer_norm""": """encoder.layers.*.layer_norm""",
    """fc1""": """encoder.layers.*.feed_forward.intermediate_dense""",
    """fc2""": """encoder.layers.*.feed_forward.output_dense""",
    """final_layer_norm""": """encoder.layers.*.final_layer_norm""",
    """encoder.layer_norm""": """encoder.layer_norm""",
    """encoder.layer_norm_for_extract""": """layer_norm_for_extract""",
    """w2v_model.layer_norm""": """feature_projection.layer_norm""",
    """quantizer.weight_proj""": """quantizer.weight_proj""",
    """quantizer.vars""": """quantizer.codevectors""",
    """project_q""": """project_q""",
    """final_proj""": """project_hid""",
    """w2v_encoder.proj""": """lm_head""",
    """label_embs_concat""": """label_embeddings_concat""",
    """mask_emb""": """masked_spec_embed""",
    """spk_proj""": """speaker_proj""",
}
__lowerCamelCase      :    Tuple   		=   [
    """lm_head""",
    """quantizer.weight_proj""",
    """quantizer.codevectors""",
    """project_q""",
    """project_hid""",
    """label_embeddings_concat""",
    """speaker_proj""",
    """layer_norm_for_extract""",
]







def   SCREAMING_SNAKE_CASE       (				snake_case_      :							Tuple  ,						snake_case_      :							Union[str, Any]  ,						snake_case_      :							Union[str, Any]  ,						snake_case_      :							Any  ,						snake_case_      :							Union[str, Any]     ):
	for attribute in key.split("."     ):
		snake_case__				:   int     =						getattr(snake_case_  ,						snake_case_     )

	if weight_type is not None:
		snake_case__				:   Optional[Any]     =						getattr(snake_case_  ,						snake_case_     ).shape
	else:
		snake_case__				:   List[str]     =						hf_pointer.shape

	if hf_shape != value.shape:
		raise ValueError(
		    F'''Shape of hf {key + '.' + weight_type if weight_type is not None else ''} is {hf_shape}, but should be'''
		    F''' {value.shape} for {full_name}'''     )

	if weight_type == "weight":
		snake_case__				:   str     =						value
	elif weight_type == "weight_g":
		snake_case__				:   Union[str, Any]     =						value
	elif weight_type == "weight_v":
		snake_case__				:   Optional[Any]     =						value
	elif weight_type == "bias":
		snake_case__				:   str     =						value
	else:
		snake_case__				:   Union[str, Any]     =						value

	logger.info(F'''{key + '.' + weight_type if weight_type is not None else ''} was initialized from {full_name}.'''     )







def   SCREAMING_SNAKE_CASE       (				snake_case_      :							Any  ,						snake_case_      :							Union[str, Any]     ):
	snake_case__				:   str     =						[]
	snake_case__				:   Optional[int]     =						fairseq_model.state_dict()

	snake_case__				:   int     =						hf_model.unispeech_sat.feature_extractor

	for name, value in fairseq_dict.items():
		snake_case__				:   Dict     =						False
		if "conv_layers" in name:
			load_conv_layer(
			    snake_case_  ,						snake_case_  ,						snake_case_  ,						snake_case_  ,						hf_model.config.feat_extract_norm == "group"  ,						)
			snake_case__				:   str     =						True
		else:
			for key, mapped_key in MAPPING.items():
				snake_case__				:   Optional[int]     =						"unispeech_sat." + mapped_key if mapped_key not in TOP_LEVEL_KEYS else mapped_key
				if key in name or key.split("w2v_model."     )[-1] == name.split("."     )[0]:
					if "layer_norm_for_extract" in name and (".".join(name.split("."     )[:-1]     ) != key):
						# special case since naming is very similar
						continue
					snake_case__				:   int     =						True
					if "*" in mapped_key:
						snake_case__				:   Any     =						name.split(snake_case_     )[0].split("."     )[-2]
						snake_case__				:   Any     =						mapped_key.replace("*"  ,						snake_case_     )
					if "weight_g" in name:
						snake_case__				:   List[Any]     =						"weight_g"
					elif "weight_v" in name:
						snake_case__				:   Optional[Any]     =						"weight_v"
					elif "bias" in name:
						snake_case__				:   Optional[Any]     =						"bias"
					elif "weight" in name:
						# TODO: don't match quantizer.weight_proj
						snake_case__				:   Optional[Any]     =						"weight"
					else:
						snake_case__				:   Optional[Any]     =						None
					set_recursively(snake_case_  ,						snake_case_  ,						snake_case_  ,						snake_case_  ,						snake_case_     )
				continue
		if not is_used:
			unused_weights.append(snake_case_     )

	logger.warning(F'''Unused weights: {unused_weights}'''     )







def   SCREAMING_SNAKE_CASE       (				snake_case_      :							Any  ,						snake_case_      :							List[str]  ,						snake_case_      :							List[Any]  ,						snake_case_      :							Optional[Any]  ,						snake_case_      :							str     ):
	snake_case__				:   Tuple     =						full_name.split("conv_layers."     )[-1]
	snake_case__				:   Union[str, Any]     =						name.split("."     )
	snake_case__				:   str     =						int(items[0]     )
	snake_case__				:   str     =						int(items[1]     )

	if type_id == 0:
		if "bias" in name:
			if value.shape != feature_extractor.conv_layers[layer_id].conv.bias.data.shape:
				raise ValueError(
				    F'''{full_name} has size {value.shape}, but'''
				    F''' {feature_extractor.conv_layers[layer_id].conv.bias.data.shape} was found.'''     )
			snake_case__				:   Any     =						value
			logger.info(F'''Feat extract conv layer {layer_id} was initialized from {full_name}.'''     )
		elif "weight" in name:
			if value.shape != feature_extractor.conv_layers[layer_id].conv.weight.data.shape:
				raise ValueError(
				    F'''{full_name} has size {value.shape}, but'''
				    F''' {feature_extractor.conv_layers[layer_id].conv.weight.data.shape} was found.'''     )
			snake_case__				:   Any     =						value
			logger.info(F'''Feat extract conv layer {layer_id} was initialized from {full_name}.'''     )
	elif (type_id == 2 and not use_group_norm) or (type_id == 2 and layer_id == 0 and use_group_norm):
		if "bias" in name:
			if value.shape != feature_extractor.conv_layers[layer_id].layer_norm.bias.data.shape:
				raise ValueError(
				    F'''{full_name} has size {value.shape}, but'''
				    F''' {feature_extractor[layer_id].layer_norm.bias.data.shape} was found.'''     )
			snake_case__				:   Optional[Any]     =						value
			logger.info(F'''Feat extract layer norm weight of layer {layer_id} was initialized from {full_name}.'''     )
		elif "weight" in name:
			if value.shape != feature_extractor.conv_layers[layer_id].layer_norm.weight.data.shape:
				raise ValueError(
				    F'''{full_name} has size {value.shape}, but'''
				    F''' {feature_extractor[layer_id].layer_norm.weight.data.shape} was found.'''     )
			snake_case__				:   int     =						value
			logger.info(F'''Feat extract layer norm weight of layer {layer_id} was initialized from {full_name}.'''     )
	else:
		unused_weights.append(snake_case_     )







@torch.no_grad()
def   SCREAMING_SNAKE_CASE       (				snake_case_      :							int  ,						snake_case_      :							Any  ,						snake_case_      :							Optional[int]=None  ,						snake_case_      :							Optional[int]=None  ,						snake_case_      :							Any=True     ):
	if config_path is not None:
		snake_case__				:   Tuple     =						UniSpeechSatConfig.from_pretrained(snake_case_     )
	else:
		snake_case__				:   Tuple     =						UniSpeechSatConfig()

	snake_case__				:   str     =						""

	if is_finetuned:
		snake_case__				:   Tuple     =						UniSpeechSatForCTC(snake_case_     )
	else:
		snake_case__				:   Any     =						UniSpeechSatForPreTraining(snake_case_     )

	snake_case__,		snake_case__,		snake_case__				:   Any     =						fairseq.checkpoint_utils.load_model_ensemble_and_task(
	    [checkpoint_path]  ,						arg_overrides={"data": "/".join(dict_path.split("/"     )[:-1]     )}     )
	snake_case__				:   Tuple     =						model[0].eval()

	recursively_load_weights(snake_case_  ,						snake_case_     )

	hf_wavavec.save_pretrained(snake_case_     )


if __name__ == "__main__":
	__lowerCamelCase      :    int   		=   argparse.ArgumentParser()
	parser.add_argument("""--pytorch_dump_folder_path""", default=None, type=str, help="""Path to the output PyTorch model.""")
	parser.add_argument("""--checkpoint_path""", default=None, type=str, help="""Path to fairseq checkpoint""")
	parser.add_argument("""--dict_path""", default=None, type=str, help="""Path to dict of fine-tuned model""")
	parser.add_argument("""--config_path""", default=None, type=str, help="""Path to hf config.json of model to convert""")
	parser.add_argument(
	    """--not_finetuned""", action="""store_true""", help="""Whether the model to convert is a fine-tuned model or not"""
	)
	__lowerCamelCase      :    List[Any]   		=   parser.parse_args()
	convert_unispeech_sat_checkpoint(
	    args.checkpoint_path, args.pytorch_dump_folder_path, args.config_path, args.dict_path, not args.not_finetuned
	)



