



"""simple docstring"""






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

import os
from pathlib import Path




def 			snake_case		(		lowerCAmelCase_  ,						lowerCAmelCase_  ,						lowerCAmelCase_	)						->				Union[str, Any]:
  _snake_case   	=      {
      '''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   	=      {
      '''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   	=      f"""{src_lang}-{tgt_lang}"""

  _snake_case   	=      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(lowerCAmelCase_  ,						exist_ok=lowerCAmelCase_	)
  _snake_case   	=      os.path.join(lowerCAmelCase_  ,						'''README.md'''	)
  print(f"""Generating {path}"""	)
  with open(lowerCAmelCase_  ,						'''w'''  ,						encoding='''utf-8'''	) as f:
    f.write(lowerCAmelCase_	)


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

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






"""simple docstring"""




from __future__ import annotations

from random import random
from typing import Generic, TypeVar

__lowerCAmelCase     :				Dict    				=    TypeVar("KT")
__lowerCAmelCase     :				Optional[Any]    				=    TypeVar("VT")

class    a_   (  Generic[KT, VT]      ):




					def __init__(						self    :  Tuple	,    snake_case__    :  KT | str = "root"	,    snake_case__    :  VT | None = None  ):
							lowerCAmelCase__   = key
							lowerCAmelCase__   = value
							lowerCAmelCase__   = []




					def __repr__(						self    :  Union[str, Any]  ):
							return F"""Node({self.key}: {self.value})"""




					@property
					def     _SCREAMING_SNAKE_CASE    (						self    :  Optional[Any]  ):
							return len(self.forward  )

class    a_   (  Generic[KT, VT]      ):




					def __init__(						self    :  int	,    snake_case__    :  float = 0.5	,    snake_case__    :  int = 16  ):
							lowerCAmelCase__   = Node[KT, VT]()
							lowerCAmelCase__   = 0
							lowerCAmelCase__   = p
							lowerCAmelCase__   = max_level




					def __str__(						self    :  int  ):
							lowerCAmelCase__   = list(self  )

							if len(snake_case__  ) == 0:
									return F"""SkipList(level={self.level})"""

							lowerCAmelCase__   = max((len(str(snake_case__  )  ) for item in items)	,    default=4  )
							lowerCAmelCase__   = max(snake_case__	,    4  ) + 4

							lowerCAmelCase__   = self.head
							lowerCAmelCase__   = []

							lowerCAmelCase__   = node.forward.copy()
							lines.append(F"""[{node.key}]""".ljust(snake_case__	,    """-"""  ) + """* """ * len(snake_case__  )  )
							lines.append(""" """ * label_size + """| """ * len(snake_case__  )  )

							while len(node.forward  ) != 0:
									lowerCAmelCase__   = node.forward[0]

									lines.append(
									    F"""[{node.key}]""".ljust(snake_case__	,    """-"""  )
									    + """ """.join(str(n.key  ) if n.key == node.key else """|""" for n in forwards  )  )
									lines.append(""" """ * label_size + """| """ * len(snake_case__  )  )
									lowerCAmelCase__   = node.forward

							lines.append("""None""".ljust(snake_case__  ) + """* """ * len(snake_case__  )  )
							return F"""SkipList(level={self.level})\n""" + "\n".join(snake_case__  )




					def __iter__(						self    :  Any  ):
							lowerCAmelCase__   = self.head

							while len(node.forward  ) != 0:
									yield node.forward[0].key
									lowerCAmelCase__   = node.forward[0]




					def     _SCREAMING_SNAKE_CASE    (						self    :  Dict  ):
							lowerCAmelCase__   = 1
							while random() < self.p and level < self.max_level:
									level += 1

							return level




					def     _SCREAMING_SNAKE_CASE    (						self    :  List[str]	,    snake_case__    :  List[str]  ):
							lowerCAmelCase__   = []

							lowerCAmelCase__   = self.head

							for i in reversed(range(self.level  )  ):
									# i < node.level - When node level is lesser than `i` decrement `i`.
									# node.forward[i].key < key - Jumping to node with key value higher
									#                             or equal to searched key would result
									#                             in skipping searched key.
									while i < node.level and node.forward[i].key < key:
											lowerCAmelCase__   = node.forward[i]
									# Each leftmost node (relative to searched node) will potentially have to
									# be updated.
									update_vector.append(snake_case__  )

							update_vector.reverse()  # Note that we were inserting values in reverse order.

							# len(node.forward) != 0 - If current node doesn't contain any further
							#                          references then searched key is not present.
							# node.forward[0].key == key - Next node key should be equal to search key
							#                              if key is present.
							if len(node.forward  ) != 0 and node.forward[0].key == key:
									return node.forward[0], update_vector
							else:
									return None, update_vector




					def     _SCREAMING_SNAKE_CASE    (						self    :  List[str]	,    snake_case__    :  KT  ):
							lowerCAmelCase__ ,       lowerCAmelCase__   = self._locate_node(snake_case__  )

							if node is not None:
									for i, update_node in enumerate(snake_case__  ):
											# Remove or replace all references to removed node.
											if update_node.level > i and update_node.forward[i].key == key:
													if node.level > i:
															lowerCAmelCase__   = node.forward[i]
													else:
															lowerCAmelCase__   = update_node.forward[:i]




					def     _SCREAMING_SNAKE_CASE    (						self    :  Union[str, Any]	,    snake_case__    :  KT	,    snake_case__    :  VT  ):
							lowerCAmelCase__ ,       lowerCAmelCase__   = self._locate_node(snake_case__  )
							if node is not None:
									lowerCAmelCase__   = value
							else:
									lowerCAmelCase__   = self.random_level()

									if level > self.level:
											# After level increase we have to add additional nodes to head.
											for _ in range(self.level - 1	,    snake_case__  ):
													update_vector.append(self.head  )
											lowerCAmelCase__   = level

									lowerCAmelCase__   = Node(snake_case__	,    snake_case__  )

									for i, update_node in enumerate(update_vector[:level]  ):
											# Change references to pass through new node.
											if update_node.level > i:
													new_node.forward.append(update_node.forward[i]  )

											if update_node.level < i + 1:
													update_node.forward.append(snake_case__  )
											else:
													lowerCAmelCase__   = new_node




					def     _SCREAMING_SNAKE_CASE    (						self    :  Union[str, Any]	,    snake_case__    :  VT  ):
							lowerCAmelCase__ ,       lowerCAmelCase__   = self._locate_node(snake_case__  )

							if node is not None:
									return node.value

							return None







def 				_UpperCAmelCase		(							):





		"""simple docstring"""




		lowerCAmelCase__   = SkipList()
		skip_list.insert("""Key1"""      ,	3  )
		skip_list.insert("""Key2"""      ,	12  )
		skip_list.insert("""Key3"""      ,	41  )
		skip_list.insert("""Key4"""      ,	-19  )

		lowerCAmelCase__   = skip_list.head
		lowerCAmelCase__   = {}
		while node.level != 0:
				lowerCAmelCase__   = node.forward[0]
				lowerCAmelCase__   = node.value

		assert len(lowerCamelCase__  ) == 4
		assert all_values["Key1"] == 3
		assert all_values["Key2"] == 12
		assert all_values["Key3"] == 41
		assert all_values["Key4"] == -19







def 				_UpperCAmelCase		(							):





		"""simple docstring"""




		lowerCAmelCase__   = SkipList()
		skip_list.insert("""Key1"""      ,	10  )
		skip_list.insert("""Key1"""      ,	12  )

		skip_list.insert("""Key5"""      ,	7  )
		skip_list.insert("""Key7"""      ,	10  )
		skip_list.insert("""Key10"""      ,	5  )

		skip_list.insert("""Key7"""      ,	7  )
		skip_list.insert("""Key5"""      ,	5  )
		skip_list.insert("""Key10"""      ,	10  )

		lowerCAmelCase__   = skip_list.head
		lowerCAmelCase__   = {}
		while node.level != 0:
				lowerCAmelCase__   = node.forward[0]
				lowerCAmelCase__   = node.value

		if len(lowerCamelCase__  ) != 4:
				print()
		assert len(lowerCamelCase__  ) == 4
		assert all_values["Key1"] == 12
		assert all_values["Key7"] == 7
		assert all_values["Key5"] == 5
		assert all_values["Key10"] == 10







def 				_UpperCAmelCase		(							):





		"""simple docstring"""




		lowerCAmelCase__   = SkipList()
		assert skip_list.find("""Some key"""  ) is None







def 				_UpperCAmelCase		(							):





		"""simple docstring"""




		lowerCAmelCase__   = SkipList()

		skip_list.insert("""Key2"""      ,	20  )
		assert skip_list.find("""Key2"""  ) == 20

		skip_list.insert("""Some Key"""      ,	10  )
		skip_list.insert("""Key2"""      ,	8  )
		skip_list.insert("""V"""      ,	13  )

		assert skip_list.find("""Y"""  ) is None
		assert skip_list.find("""Key2"""  ) == 8
		assert skip_list.find("""Some Key"""  ) == 10
		assert skip_list.find("""V"""  ) == 13







def 				_UpperCAmelCase		(							):





		"""simple docstring"""




		lowerCAmelCase__   = SkipList()
		skip_list.delete("""Some key"""  )

		assert len(skip_list.head.forward  ) == 0







def 				_UpperCAmelCase		(							):





		"""simple docstring"""




		lowerCAmelCase__   = SkipList()

		skip_list.insert("""Key1"""      ,	12  )
		skip_list.insert("""V"""      ,	13  )
		skip_list.insert("""X"""      ,	14  )
		skip_list.insert("""Key2"""      ,	15  )

		skip_list.delete("""V"""  )
		skip_list.delete("""Key2"""  )

		assert skip_list.find("""V"""  ) is None
		assert skip_list.find("""Key2"""  ) is None







def 				_UpperCAmelCase		(							):





		"""simple docstring"""




		lowerCAmelCase__   = SkipList()

		skip_list.insert("""Key1"""      ,	12  )
		skip_list.insert("""V"""      ,	13  )
		skip_list.insert("""X"""      ,	14  )
		skip_list.insert("""Key2"""      ,	15  )

		skip_list.delete("""V"""  )
		assert skip_list.find("""V"""  ) is None
		assert skip_list.find("""X"""  ) == 14
		assert skip_list.find("""Key1"""  ) == 12
		assert skip_list.find("""Key2"""  ) == 15

		skip_list.delete("""X"""  )
		assert skip_list.find("""V"""  ) is None
		assert skip_list.find("""X"""  ) is None
		assert skip_list.find("""Key1"""  ) == 12
		assert skip_list.find("""Key2"""  ) == 15

		skip_list.delete("""Key1"""  )
		assert skip_list.find("""V"""  ) is None
		assert skip_list.find("""X"""  ) is None
		assert skip_list.find("""Key1"""  ) is None
		assert skip_list.find("""Key2"""  ) == 15

		skip_list.delete("""Key2"""  )
		assert skip_list.find("""V"""  ) is None
		assert skip_list.find("""X"""  ) is None
		assert skip_list.find("""Key1"""  ) is None
		assert skip_list.find("""Key2"""  ) is None







def 				_UpperCAmelCase		(							):





		"""simple docstring"""




		lowerCAmelCase__   = SkipList()

		skip_list.insert("""Key1"""      ,	12  )
		skip_list.insert("""V"""      ,	13  )
		skip_list.insert("""X"""      ,	142  )
		skip_list.insert("""Key2"""      ,	15  )

		skip_list.delete("""X"""  )

		def traverse_keys(lowerCamelCase__  ):
				yield node.key
				for forward_node in node.forward:
						yield from traverse_keys(lowerCamelCase__  )

		assert len(set(traverse_keys(skip_list.head  )  )  ) == 4







def 				_UpperCAmelCase		(							):





		"""simple docstring"""




		def is_sorted(lowerCamelCase__  ):
				return all(next_item >= item for item, next_item in zip(lowerCamelCase__      ,	lst[1:]  )  )

		lowerCAmelCase__   = SkipList()
		for i in range(10  ):
				skip_list.insert(lowerCamelCase__      ,	lowerCamelCase__  )
		assert is_sorted(list(lowerCamelCase__  )  )
		skip_list.delete(5  )
		skip_list.delete(8  )
		skip_list.delete(2  )
		assert is_sorted(list(lowerCamelCase__  )  )
		skip_list.insert(-12      ,	-12  )
		skip_list.insert(77      ,	77  )
		assert is_sorted(list(lowerCamelCase__  )  )







def 				_UpperCAmelCase		(							):





		"""simple docstring"""




		for _ in range(100  ):
				# Repeat test 100 times due to the probabilistic nature of skip list
				# random values == random bugs
				test_insert()
				test_insert_overrides_existing_value()

				test_searching_empty_list_returns_none()
				test_search()

				test_deleting_item_from_empty_list_do_nothing()
				test_deleted_items_are_not_founded_by_find_method()
				test_delete_removes_only_given_key()
				test_delete_doesnt_leave_dead_nodes()

				test_iter_always_yields_sorted_values()







def 				_UpperCAmelCase		(							):





		"""simple docstring"""




		lowerCAmelCase__   = SkipList()
		skip_list.insert(2      ,	"""2"""  )
		skip_list.insert(4      ,	"""4"""  )
		skip_list.insert(6      ,	"""4"""  )
		skip_list.insert(4      ,	"""5"""  )
		skip_list.insert(8      ,	"""4"""  )
		skip_list.insert(9      ,	"""4"""  )

		skip_list.delete(4  )

		print(lowerCamelCase__  )


if __name__ == "__main__":
			import doctest

			doctest.testmod()
			main()




