DavidCombei commited on
Commit
5998723
·
verified ·
1 Parent(s): defede9

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +7 -0
  2. audio-detection_core/model/logreg_margin_pruning_ALL_with_scaler_threshold.joblib +3 -0
  3. audio-detection_core/model/wav2vec2-xls-r-2b_truncated/model.safetensors +3 -0
  4. avh-align_core/00042_id04939_i4v2cXo9HIQ_faceswap.mp4 +3 -0
  5. avh-align_core/assets/lipreading.gif +3 -0
  6. avh-align_core/avhubert/preparation/data/vox-en.id.gz +3 -0
  7. avh-align_core/checkpoints/avh_sup/AVH_Sup_AV1M.ckpt +3 -0
  8. avh-align_core/checkpoints/avh_sup/AVH_Sup_FAVC.ckpt +3 -0
  9. avh-align_core/fairseq/benchmark/__init__.py +7 -0
  10. avh-align_core/fairseq/benchmark/dummy_dataset.py +36 -0
  11. avh-align_core/fairseq/benchmark/dummy_lm.py +83 -0
  12. avh-align_core/fairseq/benchmark/dummy_masked_lm.py +94 -0
  13. avh-align_core/fairseq/benchmark/dummy_model.py +96 -0
  14. avh-align_core/fairseq/benchmark/dummy_mt.py +119 -0
  15. avh-align_core/fairseq/config/__init__.py +4 -0
  16. avh-align_core/fairseq/config/config.yaml +18 -0
  17. avh-align_core/fairseq/data/data_utils_fast.cpython-310-x86_64-linux-gnu.so +3 -0
  18. avh-align_core/fairseq/data/token_block_utils_fast.cpython-310-x86_64-linux-gnu.so +3 -0
  19. avh-align_core/fairseq/distributed/__init__.py +21 -0
  20. avh-align_core/fairseq/distributed/distributed_timeout_wrapper.py +94 -0
  21. avh-align_core/fairseq/distributed/fully_sharded_data_parallel.py +135 -0
  22. avh-align_core/fairseq/distributed/legacy_distributed_data_parallel.py +165 -0
  23. avh-align_core/fairseq/distributed/module_proxy_wrapper.py +55 -0
  24. avh-align_core/fairseq/distributed/tpu_distributed_data_parallel.py +43 -0
  25. avh-align_core/fairseq/distributed/utils.py +805 -0
  26. avh-align_core/fairseq/logging/__init__.py +0 -0
  27. avh-align_core/fairseq/logging/meters.py +323 -0
  28. avh-align_core/fairseq/logging/metrics.py +314 -0
  29. avh-align_core/fairseq/logging/progress_bar.py +490 -0
  30. avh-align_core/fairseq/model_parallel/criterions/__init__.py +14 -0
  31. avh-align_core/fairseq/model_parallel/criterions/vocab_parallel_cross_entropy.py +87 -0
  32. avh-align_core/fairseq/model_parallel/models/__init__.py +20 -0
  33. avh-align_core/fairseq/model_parallel/models/pipeline_parallel_transformer/__init__.py +6 -0
  34. avh-align_core/fairseq/model_parallel/models/pipeline_parallel_transformer/layers.py +600 -0
  35. avh-align_core/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py +767 -0
  36. avh-align_core/fairseq/model_parallel/models/roberta/__init__.py +6 -0
  37. avh-align_core/fairseq/model_parallel/models/roberta/model.py +225 -0
  38. avh-align_core/fairseq/model_parallel/models/transformer.py +121 -0
  39. avh-align_core/fairseq/model_parallel/models/transformer_lm.py +174 -0
  40. avh-align_core/fairseq/model_parallel/modules/__init__.py +17 -0
  41. avh-align_core/fairseq/model_parallel/modules/multihead_attention.py +349 -0
  42. avh-align_core/fairseq/model_parallel/modules/transformer_layer.py +78 -0
  43. avh-align_core/fairseq/models/__init__.py +225 -0
  44. avh-align_core/fairseq/models/bart/__init__.py +7 -0
  45. avh-align_core/fairseq/models/bart/hub_interface.py +208 -0
  46. avh-align_core/fairseq/models/bart/model.py +384 -0
  47. avh-align_core/fairseq/models/composite_encoder.py +57 -0
  48. avh-align_core/fairseq/models/distributed_fairseq_model.py +145 -0
  49. avh-align_core/fairseq/models/fairseq_decoder.py +105 -0
  50. avh-align_core/fairseq/models/fairseq_encoder.py +92 -0
.gitattributes CHANGED
@@ -34,3 +34,10 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  avh-align_core/final_podcast.mp4 filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  avh-align_core/final_podcast.mp4 filter=lfs diff=lfs merge=lfs -text
37
+ video-deepfake-detection_core/model/models--MCG-NJU--videomae-large/blobs/243706355bfd0f9399af7121df22a6d75286d5e03eaf820cad5b6c5570b3efe3 filter=lfs diff=lfs merge=lfs -text
38
+ avh-align_core/00042_id04939_i4v2cXo9HIQ_faceswap.mp4 filter=lfs diff=lfs merge=lfs -text
39
+ avh-align_core/temp_data/temp.wav filter=lfs diff=lfs merge=lfs -text
40
+ avh-align_core/model/shape_predictor_68_face_landmarks.dat filter=lfs diff=lfs merge=lfs -text
41
+ avh-align_core/assets/lipreading.gif filter=lfs diff=lfs merge=lfs -text
42
+ avh-align_core/fairseq/data/data_utils_fast.cpython-310-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
43
+ avh-align_core/fairseq/data/token_block_utils_fast.cpython-310-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
audio-detection_core/model/logreg_margin_pruning_ALL_with_scaler_threshold.joblib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:dbdc1bd864d2b997fc873499f6485891998d5f829af4746064426e942ba580dc
3
+ size 16779
audio-detection_core/model/wav2vec2-xls-r-2b_truncated/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d8c01b238f4ff6e53e52677c208fb119f21e665817d7bd11fcc8e33ea5cea3e6
3
+ size 1732225016
avh-align_core/00042_id04939_i4v2cXo9HIQ_faceswap.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:71a545b2bb07b9e491a2da74d04dbbb62c6aa40f060a34063aa6bd33f3b29cc1
3
+ size 118526
avh-align_core/assets/lipreading.gif ADDED

Git LFS Details

  • SHA256: 8cf0498b502e01bd6eb72f0985854a64793a6b4f0513181a8bc474abc3e8e75f
  • Pointer size: 132 Bytes
  • Size of remote file: 1.82 MB
avh-align_core/avhubert/preparation/data/vox-en.id.gz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:be537900d6341087b1fd06208f8a5a0dbdfe365dde61033b9156f7a2ef461262
3
+ size 3101791
avh-align_core/checkpoints/avh_sup/AVH_Sup_AV1M.ckpt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f4095aea94a1d846663995c653a2b0d1321d5112065507bdbe7de1fe0016d5ab
3
+ size 6969066
avh-align_core/checkpoints/avh_sup/AVH_Sup_FAVC.ckpt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ff6071ac565e0c3f2c711dce0dbe50bef2f5df3f972fc6f6f53790a75458ed7d
3
+ size 6969066
avh-align_core/fairseq/benchmark/__init__.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ # import models/tasks to register them
7
+ from . import dummy_dataset, dummy_lm, dummy_masked_lm, dummy_model, dummy_mt # noqa
avh-align_core/fairseq/benchmark/dummy_dataset.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from fairseq.data import FairseqDataset
3
+
4
+
5
+ class DummyDataset(FairseqDataset):
6
+ def __init__(self, batch, num_items, item_size):
7
+ super().__init__()
8
+ self.batch = batch
9
+ self.num_items = num_items
10
+ self.item_size = item_size
11
+
12
+ def __getitem__(self, index):
13
+ return index
14
+
15
+ def __len__(self):
16
+ return self.num_items
17
+
18
+ def collater(self, samples):
19
+ return self.batch
20
+
21
+ @property
22
+ def sizes(self):
23
+ return np.array([self.item_size] * self.num_items)
24
+
25
+ def num_tokens(self, index):
26
+ return self.item_size
27
+
28
+ def size(self, index):
29
+ return self.item_size
30
+
31
+ def ordered_indices(self):
32
+ return np.arange(self.num_items)
33
+
34
+ @property
35
+ def supports_prefetch(self):
36
+ return False
avh-align_core/fairseq/benchmark/dummy_lm.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import logging
7
+ from dataclasses import dataclass, field
8
+ from typing import Optional
9
+
10
+ import torch
11
+ from .dummy_dataset import DummyDataset
12
+ from fairseq.data import Dictionary
13
+ from fairseq.dataclass import FairseqDataclass
14
+ from fairseq.tasks import FairseqTask, register_task
15
+ from omegaconf import II
16
+
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ @dataclass
22
+ class DummyLMConfig(FairseqDataclass):
23
+ dict_size: int = 49996
24
+ dataset_size: int = 100000
25
+ tokens_per_sample: int = field(
26
+ default=512, metadata={"help": "max sequence length"}
27
+ )
28
+ add_bos_token: bool = False
29
+ batch_size: Optional[int] = II("dataset.batch_size")
30
+ max_tokens: Optional[int] = II("dataset.max_tokens")
31
+ max_target_positions: int = II("task.tokens_per_sample")
32
+
33
+
34
+ @register_task("dummy_lm", dataclass=DummyLMConfig)
35
+ class DummyLMTask(FairseqTask):
36
+ def __init__(self, cfg: DummyLMConfig):
37
+ super().__init__(cfg)
38
+
39
+ # load dictionary
40
+ self.dictionary = Dictionary()
41
+ for i in range(cfg.dict_size):
42
+ self.dictionary.add_symbol("word{}".format(i))
43
+ self.dictionary.pad_to_multiple_(8) # often faster if divisible by 8
44
+ logger.info("dictionary: {} types".format(len(self.dictionary)))
45
+
46
+ seq = torch.arange(cfg.tokens_per_sample + 1) + self.dictionary.pad() + 1
47
+
48
+ self.dummy_src = seq[:-1]
49
+ self.dummy_tgt = seq[1:]
50
+
51
+ def load_dataset(self, split, epoch=1, combine=False, **kwargs):
52
+ """Load a given dataset split.
53
+ Args:
54
+ split (str): name of the split (e.g., train, valid, test)
55
+ """
56
+ if self.cfg.batch_size is not None:
57
+ bsz = self.cfg.batch_size
58
+ else:
59
+ bsz = max(1, self.cfg.max_tokens // self.cfg.tokens_per_sample)
60
+ self.datasets[split] = DummyDataset(
61
+ {
62
+ "id": 1,
63
+ "net_input": {
64
+ "src_tokens": torch.stack([self.dummy_src for _ in range(bsz)]),
65
+ "src_lengths": torch.full(
66
+ (bsz,), self.cfg.tokens_per_sample, dtype=torch.long
67
+ ),
68
+ },
69
+ "target": torch.stack([self.dummy_tgt for _ in range(bsz)]),
70
+ "nsentences": bsz,
71
+ "ntokens": bsz * self.cfg.tokens_per_sample,
72
+ },
73
+ num_items=self.cfg.dataset_size,
74
+ item_size=self.cfg.tokens_per_sample,
75
+ )
76
+
77
+ @property
78
+ def source_dictionary(self):
79
+ return self.dictionary
80
+
81
+ @property
82
+ def target_dictionary(self):
83
+ return self.dictionary
avh-align_core/fairseq/benchmark/dummy_masked_lm.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import logging
7
+ from dataclasses import dataclass, field
8
+ from typing import Optional
9
+
10
+ import torch
11
+ from omegaconf import II
12
+
13
+ from .dummy_dataset import DummyDataset
14
+ from fairseq.data import Dictionary
15
+ from fairseq.dataclass import FairseqDataclass
16
+ from fairseq.tasks import FairseqTask, register_task
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ @dataclass
22
+ class DummyMaskedLMConfig(FairseqDataclass):
23
+ dict_size: int = 49996
24
+ dataset_size: int = 100000
25
+ tokens_per_sample: int = field(
26
+ default=512,
27
+ metadata={
28
+ "help": "max number of total tokens over all"
29
+ " segments per sample for BERT dataset"
30
+ },
31
+ )
32
+ batch_size: Optional[int] = II("dataset.batch_size")
33
+ max_tokens: Optional[int] = II("dataset.max_tokens")
34
+ max_target_positions: int = II("task.tokens_per_sample")
35
+
36
+
37
+ @register_task("dummy_masked_lm", dataclass=DummyMaskedLMConfig)
38
+ class DummyMaskedLMTask(FairseqTask):
39
+ def __init__(self, cfg: DummyMaskedLMConfig):
40
+ super().__init__(cfg)
41
+
42
+ self.dictionary = Dictionary()
43
+ for i in range(cfg.dict_size):
44
+ self.dictionary.add_symbol("word{}".format(i))
45
+ logger.info("dictionary: {} types".format(len(self.dictionary)))
46
+ # add mask token
47
+ self.mask_idx = self.dictionary.add_symbol("<mask>")
48
+ self.dictionary.pad_to_multiple_(8) # often faster if divisible by 8
49
+
50
+ mask_idx = 0
51
+ pad_idx = 1
52
+ seq = torch.arange(cfg.tokens_per_sample) + pad_idx + 1
53
+ mask = torch.arange(2, cfg.tokens_per_sample, 7) # ~15%
54
+ src = seq.clone()
55
+ src[mask] = mask_idx
56
+ tgt = torch.full_like(seq, pad_idx)
57
+ tgt[mask] = seq[mask]
58
+
59
+ self.dummy_src = src
60
+ self.dummy_tgt = tgt
61
+
62
+ def load_dataset(self, split, epoch=1, combine=False, **kwargs):
63
+ """Load a given dataset split.
64
+ Args:
65
+ split (str): name of the split (e.g., train, valid, test)
66
+ """
67
+ if self.cfg.batch_size is not None:
68
+ bsz = self.cfg.batch_size
69
+ else:
70
+ bsz = max(1, self.cfg.max_tokens // self.cfg.tokens_per_sample)
71
+ self.datasets[split] = DummyDataset(
72
+ {
73
+ "id": 1,
74
+ "net_input": {
75
+ "src_tokens": torch.stack([self.dummy_src for _ in range(bsz)]),
76
+ "src_lengths": torch.full(
77
+ (bsz,), self.cfg.tokens_per_sample, dtype=torch.long
78
+ ),
79
+ },
80
+ "target": torch.stack([self.dummy_tgt for _ in range(bsz)]),
81
+ "nsentences": bsz,
82
+ "ntokens": bsz * self.cfg.tokens_per_sample,
83
+ },
84
+ num_items=self.cfg.dataset_size,
85
+ item_size=self.cfg.tokens_per_sample,
86
+ )
87
+
88
+ @property
89
+ def source_dictionary(self):
90
+ return self.dictionary
91
+
92
+ @property
93
+ def target_dictionary(self):
94
+ return self.dictionary
avh-align_core/fairseq/benchmark/dummy_model.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+ from fairseq.data import Dictionary
9
+ from fairseq.models import (
10
+ FairseqDecoder,
11
+ FairseqLanguageModel,
12
+ register_model,
13
+ register_model_architecture,
14
+ )
15
+
16
+
17
+ @register_model("dummy_model")
18
+ class DummyModel(FairseqLanguageModel):
19
+ def __init__(self, args, encoder):
20
+ super().__init__(encoder)
21
+ self.args = args
22
+
23
+ @staticmethod
24
+ def add_args(parser):
25
+ parser.add_argument("--num-layers", type=int, default=24)
26
+ parser.add_argument("--embed-dim", type=int, default=1024)
27
+
28
+ @classmethod
29
+ def build_model(cls, args, task):
30
+ encoder = DummyEncoder(
31
+ num_embed=len(task.target_dictionary),
32
+ embed_dim=args.embed_dim,
33
+ num_layers=args.num_layers,
34
+ )
35
+ return cls(args, encoder)
36
+
37
+ def forward(self, src_tokens, masked_tokens=None, **kwargs):
38
+ return self.decoder(src_tokens, masked_tokens=masked_tokens)
39
+
40
+
41
+ class DummyEncoder(FairseqDecoder):
42
+ def __init__(self, num_embed=50000, embed_dim=1024, num_layers=24):
43
+ super().__init__(Dictionary())
44
+ self.embed = nn.Embedding(
45
+ num_embeddings=num_embed, embedding_dim=embed_dim, padding_idx=0
46
+ )
47
+ self.layers_a = nn.ModuleList(
48
+ [
49
+ nn.Sequential(
50
+ nn.LayerNorm(embed_dim),
51
+ nn.Linear(embed_dim, 3 * embed_dim), # q, k, v input projection
52
+ nn.Linear(3 * embed_dim, embed_dim), # skip self-attention
53
+ nn.Linear(embed_dim, embed_dim), # output projection
54
+ nn.Dropout(),
55
+ )
56
+ for i in range(num_layers)
57
+ ]
58
+ )
59
+ self.layers_b = nn.ModuleList(
60
+ [
61
+ nn.Sequential(
62
+ nn.LayerNorm(embed_dim),
63
+ nn.Linear(embed_dim, 4 * embed_dim), # FFN
64
+ nn.ReLU(),
65
+ nn.Linear(4 * embed_dim, embed_dim), # FFN
66
+ nn.Dropout(0.1),
67
+ )
68
+ for i in range(num_layers)
69
+ ]
70
+ )
71
+ self.out_proj = nn.Linear(embed_dim, num_embed)
72
+
73
+ def forward(self, tokens, masked_tokens=None):
74
+ x = self.embed(tokens)
75
+ for layer_a, layer_b in zip(self.layers_a, self.layers_b):
76
+ x = x + layer_a(x)
77
+ x = x + layer_b(x)
78
+ x = self.out_proj(x)
79
+ if masked_tokens is not None:
80
+ x = x[masked_tokens]
81
+ return (x,)
82
+
83
+ def max_positions(self):
84
+ return 1024
85
+
86
+ def get_normalized_probs(self, net_output, log_probs, sample=None):
87
+ logits = net_output[0].float()
88
+ if log_probs:
89
+ return F.log_softmax(logits, dim=-1)
90
+ else:
91
+ return F.softmax(logits, dim=-1)
92
+
93
+
94
+ @register_model_architecture("dummy_model", "dummy_model")
95
+ def base_architecture(args):
96
+ pass
avh-align_core/fairseq/benchmark/dummy_mt.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import logging
7
+
8
+ import numpy as np
9
+ import torch
10
+ from fairseq.data import Dictionary, FairseqDataset
11
+ from fairseq.tasks import LegacyFairseqTask, register_task
12
+
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ @register_task("dummy_mt")
18
+ class DummyMTTask(LegacyFairseqTask):
19
+ @staticmethod
20
+ def add_args(parser):
21
+ """Add task-specific arguments to the parser."""
22
+ parser.add_argument("--dict-size", default=49996, type=int)
23
+ parser.add_argument("--dataset-size", default=100000, type=int)
24
+ parser.add_argument("--src-len", default=30, type=int)
25
+ parser.add_argument("--tgt-len", default=30, type=int)
26
+
27
+ def __init__(self, args, dictionary):
28
+ super().__init__(args)
29
+ self.dictionary = dictionary
30
+ self.seed = args.seed
31
+
32
+ dictionary.pad_to_multiple_(8) # often faster if divisible by 8
33
+
34
+ self.dummy_src = torch.arange(args.src_len + 1) + dictionary.pad() + 1
35
+ self.dummy_tgt = torch.arange(args.tgt_len + 1) + dictionary.pad() + 1
36
+
37
+ @classmethod
38
+ def setup_task(cls, args, **kwargs):
39
+ """Setup the task. """
40
+ dictionary = Dictionary()
41
+ for i in range(args.dict_size):
42
+ dictionary.add_symbol("word{}".format(i))
43
+ logger.info("dictionary: {} types".format(len(dictionary)))
44
+
45
+ args.max_source_positions = args.src_len + dictionary.pad() + 2
46
+ args.max_target_positions = args.tgt_len + dictionary.pad() + 2
47
+
48
+ return cls(args, dictionary)
49
+
50
+ def load_dataset(self, split, epoch=1, combine=False, **kwargs):
51
+ """Load a given dataset split.
52
+ Args:
53
+ split (str): name of the split (e.g., train, valid, test)
54
+ """
55
+ item_size = max(self.args.src_len, self.args.tgt_len)
56
+ if self.args.batch_size is not None:
57
+ bsz = self.args.batch_size
58
+ else:
59
+ bsz = max(1, self.args.max_tokens // item_size)
60
+ tgt = torch.stack([self.dummy_tgt for _ in range(bsz)])
61
+ self.datasets[split] = DummyDataset(
62
+ {
63
+ "id": 1,
64
+ "net_input": {
65
+ "src_tokens": torch.stack([self.dummy_src for _ in range(bsz)]),
66
+ "src_lengths": torch.full(
67
+ (bsz,), self.args.src_len, dtype=torch.long
68
+ ),
69
+ "prev_output_tokens": tgt.clone(),
70
+ },
71
+ "target": tgt,
72
+ "nsentences": bsz,
73
+ "ntokens": bsz * self.args.tgt_len,
74
+ },
75
+ num_items=self.args.dataset_size,
76
+ item_size=item_size,
77
+ )
78
+
79
+ @property
80
+ def source_dictionary(self):
81
+ return self.dictionary
82
+
83
+ @property
84
+ def target_dictionary(self):
85
+ return self.dictionary
86
+
87
+
88
+ class DummyDataset(FairseqDataset):
89
+ def __init__(self, batch, num_items, item_size):
90
+ super().__init__()
91
+ self.batch = batch
92
+ self.num_items = num_items
93
+ self.item_size = item_size
94
+
95
+ def __getitem__(self, index):
96
+ return index
97
+
98
+ def __len__(self):
99
+ return self.num_items
100
+
101
+ def collater(self, samples):
102
+ return self.batch
103
+
104
+ @property
105
+ def sizes(self):
106
+ return np.array([self.item_size] * self.num_items)
107
+
108
+ def num_tokens(self, index):
109
+ return self.item_size
110
+
111
+ def size(self, index):
112
+ return self.item_size
113
+
114
+ def ordered_indices(self):
115
+ return np.arange(self.num_items)
116
+
117
+ @property
118
+ def supports_prefetch(self):
119
+ return False
avh-align_core/fairseq/config/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
avh-align_core/fairseq/config/config.yaml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # @package _group_
2
+
3
+ hydra:
4
+ run:
5
+ dir: .
6
+
7
+ defaults:
8
+ - task: null
9
+ - model: null
10
+ - criterion: cross_entropy
11
+ - optimizer: null
12
+ - lr_scheduler: fixed
13
+ - bpe: null
14
+ - tokenizer: null
15
+ - scoring: null
16
+ - generation: null
17
+ - common_eval: null
18
+ - eval_lm: null
avh-align_core/fairseq/data/data_utils_fast.cpython-310-x86_64-linux-gnu.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:69558d8f04e3b4faf3dd6e2cd5afa87575eda8706300bdb9190c85a0d063bc24
3
+ size 262128
avh-align_core/fairseq/data/token_block_utils_fast.cpython-310-x86_64-linux-gnu.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:181413dbe125f7b3f485407d0cfa313aa720456a86a3b4a0e761d370fc9baca2
3
+ size 280360
avh-align_core/fairseq/distributed/__init__.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ from .distributed_timeout_wrapper import DistributedTimeoutWrapper
7
+ from .fully_sharded_data_parallel import fsdp_enable_wrap, fsdp_wrap, FullyShardedDataParallel
8
+ from .legacy_distributed_data_parallel import LegacyDistributedDataParallel
9
+ from .module_proxy_wrapper import ModuleProxyWrapper
10
+ from .tpu_distributed_data_parallel import TPUDistributedDataParallel
11
+
12
+
13
+ __all__ = [
14
+ "DistributedTimeoutWrapper",
15
+ "fsdp_enable_wrap",
16
+ "fsdp_wrap",
17
+ "FullyShardedDataParallel",
18
+ "LegacyDistributedDataParallel",
19
+ "ModuleProxyWrapper",
20
+ "TPUDistributedDataParallel",
21
+ ]
avh-align_core/fairseq/distributed/distributed_timeout_wrapper.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import logging
7
+ import os
8
+ import signal
9
+ import threading
10
+
11
+ from torch import nn
12
+
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class DistributedTimeoutWrapper(nn.Module):
18
+ """
19
+ A wrapper that kills the process if no progress is made within a given
20
+ *timeout*. The timer is reset every time :func:`forward` is called.
21
+
22
+ Usage::
23
+
24
+ module = DistributedTimeoutWrapper(module, timeout=30)
25
+ x = module(input)
26
+ time.sleep(20) # safe
27
+ x = module(input)
28
+ time.sleep(45) # job will be killed before this returns
29
+
30
+ Args:
31
+ module (nn.Module): module to wrap
32
+ timeout (int): number of seconds before killing the process
33
+ (set to a value <= 0 to disable the timeout)
34
+ signal (Optional): signal to send once timeout is triggered
35
+ """
36
+ def __init__(self, module: nn.Module, timeout: int, signal=signal.SIGINT):
37
+ super().__init__()
38
+ self.module = module
39
+ self.timeout = timeout
40
+ self.signal = signal
41
+
42
+ if timeout > 0:
43
+ self._heartbeat = threading.Event()
44
+ self._heartbeat_thread = threading.Thread(
45
+ target=self._check_heartbeat,
46
+ args=(os.getpid(),),
47
+ daemon=True,
48
+ )
49
+ self._heartbeat_thread.start()
50
+ self._terminated = False
51
+ else:
52
+ self._heartbeat = None
53
+ self._heartbeat_thread = None
54
+
55
+ def __del__(self):
56
+ self.stop_timeout()
57
+
58
+ def __getattr__(self, name):
59
+ """Forward missing attributes to wrapped module."""
60
+ try:
61
+ return super().__getattr__(name) # defer to nn.Module's logic
62
+ except AttributeError:
63
+ return getattr(self.module, name)
64
+
65
+ def stop_timeout(self):
66
+ if self._heartbeat_thread is not None:
67
+ self._terminated = True
68
+ self._heartbeat_thread.join()
69
+
70
+ def state_dict(self, *args, **kwargs):
71
+ return self.module.state_dict(*args, **kwargs)
72
+
73
+ def load_state_dict(self, *args, **kwargs):
74
+ return self.module.load_state_dict(*args, **kwargs)
75
+
76
+ def forward(self, *args, **kwargs):
77
+ if self._heartbeat is not None:
78
+ self._heartbeat.set()
79
+ return self.module(*args, **kwargs)
80
+
81
+ def _check_heartbeat(self, parent_pid):
82
+ self._heartbeat.wait() # wait for the first forward pass
83
+ while True:
84
+ self._heartbeat.clear()
85
+ success = self._heartbeat.wait(timeout=self.timeout)
86
+ if self._terminated:
87
+ break
88
+ elif not success:
89
+ logger.error((
90
+ "Killing job for not making progress in {} seconds. "
91
+ "Set --heartbeat-timeout=-1 to disable this timeout."
92
+ ).format(int(self.timeout)))
93
+ os.kill(parent_pid, self.signal)
94
+ return
avh-align_core/fairseq/distributed/fully_sharded_data_parallel.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import contextlib
7
+ from typing import Optional
8
+
9
+ import torch
10
+ from fairseq.dataclass.configs import DistributedTrainingConfig
11
+ from fairseq.distributed import utils as dist_utils
12
+
13
+
14
+ try:
15
+ from fairscale.nn.data_parallel import FullyShardedDataParallel as FSDP
16
+
17
+ has_FSDP = True
18
+ except ImportError:
19
+ FSDP = torch.nn.Module
20
+ has_FSDP = False
21
+
22
+
23
+ class FullyShardedDataParallel(FSDP):
24
+ """
25
+ A small wrapper around fairscale's FullyShardedDataParallel (FSDP) with some
26
+ fairseq-specific checkpoint saving/loading logic.
27
+
28
+ Args:
29
+ use_sharded_state (bool): if True, then ``state_dict`` will return
30
+ ``FSDP.local_state_dict`` and ``load_state_dict`` will call
31
+ ``FSDP.load_local_state_dict``. Otherwise, ``state_dict`` will
32
+ return the full model weights on data parallel rank 0 (empty on
33
+ other ranks) and ``load_state_dict`` will broadcast model weights
34
+ from rank 0 to other ranks.
35
+ """
36
+
37
+ def __init__(self, *args, use_sharded_state: bool = False, **kwargs):
38
+ if not has_FSDP:
39
+ raise ImportError(
40
+ "Cannot find FullyShardedDataParallel. "
41
+ "Please install fairscale with: pip install fairscale"
42
+ )
43
+ super().__init__(*args, **kwargs)
44
+ self.use_sharded_state = use_sharded_state
45
+
46
+ @property
47
+ def unwrapped_module(self) -> torch.nn.Module:
48
+ if self.flatten_parameters:
49
+ return self.module.module
50
+ else:
51
+ return self.module
52
+
53
+ def state_dict(self, destination=None, prefix="", keep_vars=False):
54
+ if self.use_sharded_state:
55
+ return super().local_state_dict(
56
+ destination=destination, prefix=prefix, keep_vars=keep_vars
57
+ )
58
+ else:
59
+ if self.rank == 0:
60
+ return super().state_dict(
61
+ destination=destination, prefix=prefix, keep_vars=keep_vars
62
+ )
63
+ else:
64
+ # We must call state_dict() due to use of communication
65
+ # primitives. But we don't use the result.
66
+ super().state_dict()
67
+ return destination or {}
68
+
69
+ def load_state_dict(self, state_dict, strict=True, model_cfg=None):
70
+ if self.use_sharded_state:
71
+ return super().load_local_state_dict(state_dict, strict=strict)
72
+ else:
73
+ state_dict = dist_utils.broadcast_object(
74
+ state_dict, src_rank=0, group=self.process_group
75
+ )
76
+ return super().load_state_dict(state_dict, strict=strict)
77
+
78
+
79
+ @contextlib.contextmanager
80
+ def fsdp_enable_wrap(cfg: DistributedTrainingConfig):
81
+ try:
82
+ from fairscale.nn import enable_wrap
83
+ except ImportError:
84
+ raise ImportError(
85
+ "Cannot find FullyShardedDataParallel. "
86
+ "Please install fairscale with: pip install fairscale"
87
+ )
88
+ if cfg.memory_efficient_fp16:
89
+ assert cfg.fp16 # memory_efficient_fp16 should imply fp16
90
+ group = dist_utils.get_data_parallel_group()
91
+ if group is None and cfg.distributed_world_size == 1:
92
+ from fairscale.utils.testing import DummyProcessGroup
93
+
94
+ group = DummyProcessGroup(rank=0, size=1)
95
+ fsdp_config = {
96
+ "process_group": group,
97
+ "reshard_after_forward": not cfg.no_reshard_after_forward,
98
+ "mixed_precision": cfg.fp16 and not cfg.memory_efficient_fp16,
99
+ "fp32_reduce_scatter": cfg.fp32_reduce_scatter,
100
+ "flatten_parameters": True,
101
+ "cpu_offload": cfg.cpu_offload,
102
+ "compute_dtype": torch.float16 if cfg.fp16 else torch.float32,
103
+ "bucket_cap_mb": cfg.bucket_cap_mb,
104
+ "state_dict_device": torch.device("cpu"), # reduce GPU mem usage
105
+ }
106
+ with enable_wrap(
107
+ wrapper_cls=FullyShardedDataParallel,
108
+ use_sharded_state=cfg.use_sharded_state,
109
+ **fsdp_config,
110
+ ):
111
+ yield
112
+
113
+
114
+ def fsdp_wrap(module, min_num_params: Optional[int] = None, **kwargs):
115
+ """
116
+ Helper to wrap layers/modules in FSDP. This falls back to a no-op if
117
+ fairscale is not available.
118
+
119
+ Args:
120
+ module (nn.Module): module to (maybe) wrap
121
+ min_num_params (int, Optional): minimum number of layer params to wrap
122
+ """
123
+ try:
124
+ from fairscale.nn import wrap
125
+
126
+ if min_num_params is not None:
127
+ num_params = sum(p.numel() for p in module.parameters())
128
+ if num_params >= min_num_params:
129
+ return wrap(module, **kwargs)
130
+ else:
131
+ return module
132
+ else:
133
+ return wrap(module, **kwargs)
134
+ except ImportError:
135
+ return module
avh-align_core/fairseq/distributed/legacy_distributed_data_parallel.py ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ """
7
+ A modified version of the legacy DistributedDataParallel module that uses c10d
8
+ communication primitives. This version is simpler than the latest PyTorch
9
+ version and is useful for debugging. Notably it does not overlap gradient
10
+ communication with the backward pass, which makes it slower but more robust
11
+ than the PyTorch version.
12
+
13
+ This version also supports the *no_sync* context manager, which allows faster
14
+ training with `--update-freq`.
15
+ """
16
+
17
+ from collections import OrderedDict
18
+ from contextlib import contextmanager
19
+
20
+ import torch
21
+ from torch import nn
22
+
23
+ from fairseq.distributed import utils
24
+
25
+
26
+ class LegacyDistributedDataParallel(nn.Module):
27
+ """Implements distributed data parallelism at the module level.
28
+
29
+ A simplified version of :class:`torch.nn.parallel.DistributedDataParallel`.
30
+ This version uses a c10d process group for communication and does not
31
+ broadcast buffers.
32
+
33
+ Args:
34
+ module (~torch.nn.Module): module to be parallelized
35
+ process_group: the c10d process group to be used for distributed data
36
+ parallel all-reduction.
37
+ buffer_size (int, optional): number of elements to buffer before
38
+ performing all-reduce (default: 256M).
39
+ """
40
+
41
+ def __init__(self, module, process_group, buffer_size=2 ** 28):
42
+ super().__init__()
43
+
44
+ self.module = module
45
+ self.process_group = process_group
46
+ self.world_size = utils.get_world_size(self.process_group)
47
+
48
+ # Never use a bigger buffer than the number of model params
49
+ self.buffer_size = min(buffer_size, sum(p.numel() for p in module.parameters()))
50
+ self.buffer = None
51
+
52
+ # We can also forcibly accumulate grads locally and only do the
53
+ # all-reduce at some later time
54
+ self.accumulate_grads = False
55
+
56
+ # make per-device lists of parameters
57
+ paramlists = OrderedDict()
58
+ for param in self.module.parameters():
59
+ device = param.device
60
+ if paramlists.get(device) is None:
61
+ paramlists[device] = []
62
+ paramlists[device] += [param]
63
+ self.per_device_params = list(paramlists.values())
64
+
65
+ @contextmanager
66
+ def no_sync(self):
67
+ """A context manager to disable gradient synchronization."""
68
+ old_accumulate_grads = self.accumulate_grads
69
+ self.accumulate_grads = True
70
+ yield
71
+ self.accumulate_grads = old_accumulate_grads
72
+
73
+ def forward(self, *inputs, **kwargs):
74
+ return self.module(*inputs, **kwargs)
75
+
76
+ def all_reduce_grads(self):
77
+ """
78
+ This function must be called explicitly after backward to reduce
79
+ gradients. There is no automatic hook like c10d.
80
+ """
81
+
82
+ def all_reduce_params(params):
83
+ buffer = self.buffer
84
+ nonzero_buffer = False
85
+ if len(params) > 1:
86
+ offset = 0
87
+ for p in params:
88
+ sz = p.numel()
89
+ if p.grad is not None:
90
+ buffer[offset : offset + sz].copy_(p.grad.data.view(-1))
91
+ nonzero_buffer = True
92
+ else:
93
+ buffer[offset : offset + sz].zero_()
94
+ offset += sz
95
+ else:
96
+ # we only have a single grad to all-reduce
97
+ p = params[0]
98
+ if p.grad is not None:
99
+ buffer = p.grad.data
100
+ nonzero_buffer = True
101
+ elif p.numel() <= self.buffer.numel():
102
+ buffer = buffer[: p.numel()]
103
+ buffer.zero_()
104
+ else:
105
+ buffer = torch.zeros_like(p)
106
+
107
+ if nonzero_buffer:
108
+ buffer.div_(self.world_size)
109
+
110
+ utils.all_reduce(buffer, self.process_group)
111
+
112
+ # copy all-reduced grads back into their original place
113
+ offset = 0
114
+ for p in params:
115
+ sz = p.numel()
116
+ if p.grad is not None:
117
+ p.grad.data.copy_(buffer[offset : offset + sz].view_as(p))
118
+ else:
119
+ p.grad = buffer[offset : offset + sz].view_as(p).clone()
120
+ offset += sz
121
+
122
+ def reduction_fn():
123
+ # This function only needs to be called once
124
+ if self.accumulate_grads:
125
+ return
126
+
127
+ if self.buffer is None:
128
+ self.buffer = next(self.module.parameters()).new(self.buffer_size)
129
+
130
+ for params in self.per_device_params:
131
+ # All-reduce the gradients in buckets
132
+ offset = 0
133
+ buffered_params = []
134
+ for param in params:
135
+ if not param.requires_grad:
136
+ continue
137
+ if param.grad is None:
138
+ param.grad = torch.zeros_like(param)
139
+
140
+ if hasattr(param, 'expert'):
141
+ # Skip gradient sync for unshared parameters
142
+ continue
143
+
144
+ if param.grad.requires_grad:
145
+ raise RuntimeError(
146
+ "DistributedDataParallel only works "
147
+ "with gradients that don't require "
148
+ "grad"
149
+ )
150
+ sz = param.numel()
151
+ if sz > self.buffer.numel():
152
+ # all-reduce big params directly
153
+ all_reduce_params([param])
154
+ else:
155
+ if offset + sz > self.buffer.numel():
156
+ all_reduce_params(buffered_params)
157
+ offset = 0
158
+ buffered_params.clear()
159
+ buffered_params.append(param)
160
+ offset += sz
161
+
162
+ if len(buffered_params) > 0:
163
+ all_reduce_params(buffered_params)
164
+
165
+ reduction_fn()
avh-align_core/fairseq/distributed/module_proxy_wrapper.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ from torch import nn
7
+
8
+
9
+ class ModuleProxyWrapper(nn.Module):
10
+ """
11
+ Wrap a DistributedDataParallel module and forward requests for missing
12
+ attributes to the module wrapped by DDP (the twice-wrapped module).
13
+ Also forward calls to :func:`state_dict` and :func:`load_state_dict`.
14
+
15
+ Usage::
16
+
17
+ module.xyz = "hello world"
18
+ wrapped_module = DistributedDataParallel(module, **ddp_args)
19
+ wrapped_module = ModuleProxyWrapper(wrapped_module)
20
+ assert wrapped_module.xyz == "hello world"
21
+ assert wrapped_module.state_dict().keys() == module.state_dict().keys()
22
+
23
+ Args:
24
+ module (nn.Module): module to wrap
25
+ """
26
+
27
+ def __init__(self, module: nn.Module):
28
+ super().__init__()
29
+ assert hasattr(module, "module"), \
30
+ "ModuleProxyWrapper expects input to wrap another module"
31
+ self.module = module
32
+
33
+ def __getattr__(self, name):
34
+ """Forward missing attributes to twice-wrapped module."""
35
+ try:
36
+ # defer to nn.Module's logic
37
+ return super().__getattr__(name)
38
+ except AttributeError:
39
+ try:
40
+ # forward to the once-wrapped module
41
+ return getattr(self.module, name)
42
+ except AttributeError:
43
+ # forward to the twice-wrapped module
44
+ return getattr(self.module.module, name)
45
+
46
+ def state_dict(self, *args, **kwargs):
47
+ """Forward to the twice-wrapped module."""
48
+ return self.module.module.state_dict(*args, **kwargs)
49
+
50
+ def load_state_dict(self, *args, **kwargs):
51
+ """Forward to the twice-wrapped module."""
52
+ return self.module.module.load_state_dict(*args, **kwargs)
53
+
54
+ def forward(self, *args, **kwargs):
55
+ return self.module(*args, **kwargs)
avh-align_core/fairseq/distributed/tpu_distributed_data_parallel.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import torch
7
+ from torch import nn
8
+
9
+ from fairseq.distributed import utils
10
+
11
+
12
+ class TPUDistributedDataParallel(nn.Module):
13
+
14
+ def __init__(self, module, process_group):
15
+ super().__init__()
16
+ self.module = module
17
+ self.process_group = process_group
18
+ self.world_size = utils.get_world_size(self.process_group)
19
+
20
+ def forward(self, *inputs, **kwargs):
21
+ return self.module(*inputs, **kwargs)
22
+
23
+ def all_reduce_grads(self):
24
+ gradients = []
25
+ for p in self.parameters():
26
+ if not p.requires_grad:
27
+ continue
28
+ if p.grad is None:
29
+ p.grad = torch.zeros_like(p)
30
+ if p.grad.requires_grad:
31
+ raise RuntimeError(
32
+ "TPUDistributedDataParallel only works with gradients that don't "
33
+ "require grad"
34
+ )
35
+ gradients.append(p.grad)
36
+
37
+ import torch_xla.core.xla_model as xm
38
+ xm.all_reduce(
39
+ 'sum',
40
+ gradients,
41
+ scale=1. / self.world_size,
42
+ groups=self.process_group[1],
43
+ )
avh-align_core/fairseq/distributed/utils.py ADDED
@@ -0,0 +1,805 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import io
7
+ import logging
8
+ import os
9
+ import pickle
10
+ import random
11
+ import socket
12
+ import struct
13
+ import subprocess
14
+ import warnings
15
+ from argparse import Namespace
16
+ from collections import OrderedDict
17
+ from dataclasses import dataclass
18
+ from typing import Any, Dict, List, Mapping, Optional
19
+
20
+ import torch
21
+ import torch.distributed as dist
22
+ from fairseq.dataclass.configs import DistributedTrainingConfig, FairseqConfig
23
+ from omegaconf import open_dict
24
+
25
+ try:
26
+ import torch_xla.core.xla_model as xm
27
+ except ImportError:
28
+ xm = None
29
+
30
+
31
+ # Flag to indicate if we're using Megatron
32
+ # NOTE: this is a temporary hack until we move away from Megatron's model parallel init
33
+ _USE_MEGATRON = False
34
+
35
+ # Whether to use XLA ops (e.g., on TPUs) instead of CUDA ops.
36
+ _USE_XLA = False
37
+
38
+
39
+ logger = logging.getLogger(__name__)
40
+
41
+
42
+ def is_master(cfg: DistributedTrainingConfig):
43
+ return cfg.distributed_rank == 0
44
+
45
+
46
+ def infer_init_method(cfg: DistributedTrainingConfig, force_distributed=False):
47
+ if cfg.distributed_init_method is not None or cfg.tpu:
48
+ return
49
+
50
+ num_pipelines_per_node = None
51
+ if cfg.pipeline_model_parallel:
52
+ num_pipeline_devices, num_pipelines_per_node = _pipeline_parallel_pre_init(cfg)
53
+
54
+ if all(
55
+ key in os.environ
56
+ for key in ["MASTER_ADDR", "MASTER_PORT", "WORLD_SIZE", "RANK"]
57
+ ):
58
+ # support torch.distributed.launch
59
+ _infer_torch_distributed_launch_init(cfg)
60
+ elif cfg.distributed_port > 0:
61
+ # we can determine the init method automatically for Slurm
62
+ _infer_slurm_init(cfg, num_pipelines_per_node)
63
+ elif cfg.distributed_world_size > 1 or force_distributed:
64
+ # fallback for single node with multiple GPUs
65
+ _infer_single_node_init(cfg)
66
+
67
+ if cfg.pipeline_model_parallel:
68
+ _pipeline_parallel_post_init(cfg, num_pipeline_devices, num_pipelines_per_node)
69
+ elif not cfg.distributed_no_spawn:
70
+ with open_dict(cfg):
71
+ cfg.distributed_num_procs = min(
72
+ torch.cuda.device_count(), cfg.distributed_world_size
73
+ )
74
+
75
+
76
+ def _infer_torch_distributed_launch_init(cfg: DistributedTrainingConfig):
77
+ cfg.distributed_init_method = "env://"
78
+ cfg.distributed_world_size = int(os.environ["WORLD_SIZE"])
79
+ cfg.distributed_rank = int(os.environ["RANK"])
80
+ # processes are created by torch.distributed.launch
81
+ cfg.distributed_no_spawn = True
82
+
83
+
84
+ def _infer_slurm_init(cfg: DistributedTrainingConfig, num_pipelines_per_node):
85
+ node_list = os.environ.get("SLURM_STEP_NODELIST")
86
+ if node_list is None:
87
+ node_list = os.environ.get("SLURM_JOB_NODELIST")
88
+ if node_list is not None:
89
+ try:
90
+ hostnames = subprocess.check_output(
91
+ ["scontrol", "show", "hostnames", node_list]
92
+ )
93
+ cfg.distributed_init_method = "tcp://{host}:{port}".format(
94
+ host=hostnames.split()[0].decode("utf-8"),
95
+ port=cfg.distributed_port,
96
+ )
97
+ nnodes = int(os.environ.get("SLURM_NNODES"))
98
+ ntasks_per_node = os.environ.get("SLURM_NTASKS_PER_NODE")
99
+ if ntasks_per_node is not None:
100
+ ntasks_per_node = int(ntasks_per_node)
101
+ else:
102
+ ntasks = int(os.environ.get("SLURM_NTASKS"))
103
+ nnodes = int(os.environ.get("SLURM_NNODES"))
104
+ assert ntasks % nnodes == 0
105
+ ntasks_per_node = int(ntasks / nnodes)
106
+ if ntasks_per_node == 1:
107
+ gpus_per_node = torch.cuda.device_count()
108
+ node_id = int(os.environ.get("SLURM_NODEID"))
109
+ cfg.distributed_rank = node_id * gpus_per_node
110
+ cfg.distributed_world_size = nnodes * gpus_per_node
111
+ elif cfg.pipeline_model_parallel:
112
+ assert ntasks_per_node == num_pipelines_per_node, (
113
+ "SLURM --ntasks-per-node must match number of pipelines per "
114
+ "node (={})".format(num_pipelines_per_node)
115
+ )
116
+ cfg.distributed_no_spawn = True
117
+ # For 4-way MP on nodes with 8 GPUs, ranks will be [0, 1] on
118
+ # the first node, [1, 2] on the second node, etc. This
119
+ # matches torch.distributed.launch.
120
+ node_id = int(os.environ.get("SLURM_NODEID"))
121
+ local_id = int(os.environ.get("SLURM_LOCALID"))
122
+ cfg.distributed_rank = node_id * num_pipelines_per_node + local_id
123
+ # In the above example, device_id will always be in [0, 1],
124
+ # which also matches torch.distributed.launch.
125
+ cfg.device_id = local_id
126
+ # We also want to set distributed_world_size to be the total
127
+ # number of pipelines across all nodes.
128
+ cfg.distributed_world_size = nnodes * num_pipelines_per_node
129
+ else:
130
+ assert ntasks_per_node == cfg.distributed_world_size // nnodes
131
+ cfg.distributed_no_spawn = True
132
+ cfg.distributed_rank = int(os.environ.get("SLURM_PROCID"))
133
+ cfg.device_id = int(os.environ.get("SLURM_LOCALID"))
134
+ except subprocess.CalledProcessError as e: # scontrol failed
135
+ raise e
136
+ except FileNotFoundError: # Slurm is not installed
137
+ pass
138
+
139
+
140
+ def _infer_single_node_init(cfg: DistributedTrainingConfig):
141
+ assert (
142
+ cfg.distributed_world_size <= torch.cuda.device_count()
143
+ ), f"world size is {cfg.distributed_world_size} but have {torch.cuda.device_count()} available devices"
144
+ port = random.randint(10000, 20000)
145
+ cfg.distributed_init_method = "tcp://localhost:{port}".format(port=port)
146
+
147
+
148
+ def _pipeline_parallel_pre_init(cfg: DistributedTrainingConfig):
149
+ from fairseq import utils
150
+
151
+ balance_exists = (
152
+ cfg.pipeline_balance is not None
153
+ or cfg.pipeline_encoder_balance is not None
154
+ or cfg.pipeline_decoder_balance is not None
155
+ )
156
+ devices_exist = (
157
+ cfg.pipeline_devices is not None
158
+ or cfg.pipeline_encoder_devices is not None
159
+ or cfg.pipeline_decoder_devices is not None
160
+ )
161
+ if not balance_exists:
162
+ raise ValueError(
163
+ "--pipeline-balance is currently required for pipeline model parallelism"
164
+ )
165
+ if not devices_exist:
166
+ raise ValueError(
167
+ "--pipeline-devices is currently required for pipeline model parallelism"
168
+ )
169
+
170
+ cfg.pipeline_balance = utils.eval_str_list(cfg.pipeline_balance, type=int)
171
+ if cfg.pipeline_devices is not None:
172
+ cfg.pipeline_devices = utils.eval_str_list(cfg.pipeline_devices, type=int)
173
+ num_pipeline_devices = len(set(cfg.pipeline_devices))
174
+ else:
175
+ cfg.pipeline_encoder_devices = utils.eval_str_list(
176
+ cfg.pipeline_encoder_devices, type=int
177
+ )
178
+ cfg.pipeline_decoder_devices = utils.eval_str_list(
179
+ cfg.pipeline_decoder_devices, type=int
180
+ )
181
+ num_pipeline_devices = len(
182
+ set(cfg.pipeline_encoder_devices + cfg.pipeline_decoder_devices)
183
+ )
184
+ gpus_per_node = torch.cuda.device_count()
185
+ assert (
186
+ gpus_per_node >= num_pipeline_devices
187
+ and gpus_per_node % num_pipeline_devices == 0
188
+ ), (
189
+ "the number of unique device IDs in --pipeline-devices must evenly divide "
190
+ "the number of GPUs per node (multi-node pipelining is not yet supported)"
191
+ )
192
+ num_pipelines_per_node = gpus_per_node // num_pipeline_devices
193
+ return num_pipeline_devices, num_pipelines_per_node
194
+
195
+
196
+ def _pipeline_parallel_post_init(
197
+ cfg: DistributedTrainingConfig, num_pipeline_devices, num_pipelines_per_node
198
+ ):
199
+ if not cfg.distributed_no_spawn:
200
+ # When distributed_no_spawn is False, we expect distributed_rank and
201
+ # distributed_world_size to be based on the total number of GPUs, so
202
+ # we need to correct them to be based on the number of pipelines.
203
+ assert cfg.distributed_world_size % num_pipeline_devices == 0
204
+ cfg.distributed_world_size = (
205
+ cfg.distributed_world_size // num_pipeline_devices
206
+ )
207
+ # In the case of 4-way MP on nodes with 8 GPUs, we want
208
+ # distributed_rank to be the starting GPU index for each pipeline
209
+ # i.e., 0, 2, ...
210
+ gpus_per_node = torch.cuda.device_count()
211
+ assert cfg.distributed_rank % gpus_per_node == 0
212
+ assert cfg.distributed_rank % num_pipeline_devices == 0
213
+
214
+ with open_dict(cfg):
215
+ cfg.distributed_rank = cfg.distributed_rank // num_pipeline_devices
216
+ # launch one process per pipeline
217
+ cfg.distributed_num_procs = num_pipelines_per_node
218
+
219
+ # if we have 4-way MP on a node with 8 GPUs, we want device_ids to be 0
220
+ # and 4, indicating the starting device IDs for each pipeline
221
+ cfg.device_id *= num_pipeline_devices
222
+
223
+ if cfg.device_id > 0:
224
+ # if there's multiple pipelines on a node (e.g., 4-way MP on an 8
225
+ # GPU node), we need to adjust pipeline_devices accordingly
226
+ logger.debug(
227
+ "setting CUDA device={} on rank {}".format(
228
+ cfg.device_id, cfg.distributed_rank
229
+ )
230
+ )
231
+ torch.cuda.set_device(cfg.device_id)
232
+ with open_dict(cfg):
233
+ cfg.pipeline_devices = [cfg.device_id + d for d in cfg.pipeline_devices]
234
+ logger.info(
235
+ "setting pipeline_devices={} on rank {}".format(
236
+ cfg.pipeline_devices, cfg.distributed_rank
237
+ )
238
+ )
239
+
240
+
241
+ def distributed_init(cfg: FairseqConfig):
242
+ if isinstance(cfg, Namespace):
243
+ from fairseq.dataclass.utils import convert_namespace_to_omegaconf
244
+
245
+ cfg = convert_namespace_to_omegaconf(cfg)
246
+
247
+ if not cfg.common.tpu:
248
+ if torch.distributed.is_available() and torch.distributed.is_initialized():
249
+ warnings.warn(
250
+ "Distributed is already initialized, cannot initialize twice!"
251
+ )
252
+ else:
253
+ logger.info(
254
+ "distributed init (rank {}): {}".format(
255
+ cfg.distributed_training.distributed_rank,
256
+ cfg.distributed_training.distributed_init_method,
257
+ )
258
+ )
259
+ dist.init_process_group(
260
+ backend=cfg.distributed_training.distributed_backend,
261
+ init_method=cfg.distributed_training.distributed_init_method,
262
+ world_size=cfg.distributed_training.distributed_world_size,
263
+ rank=cfg.distributed_training.distributed_rank,
264
+ )
265
+ logger.info(
266
+ "initialized host {} as rank {}".format(
267
+ socket.gethostname(),
268
+ cfg.distributed_training.distributed_rank,
269
+ )
270
+ )
271
+
272
+ # perform a dummy all-reduce to initialize the NCCL communicator
273
+ if torch.cuda.is_available():
274
+ dist.all_reduce(torch.zeros(1).cuda())
275
+
276
+ cfg.distributed_training.distributed_rank = torch.distributed.get_rank()
277
+ else:
278
+ assert xm.xrt_world_size() == cfg.distributed_training.distributed_world_size
279
+ global _USE_XLA
280
+ _USE_XLA = True
281
+ cfg.distributed_training.device_id = xm.get_local_ordinal()
282
+ cfg.distributed_training.distributed_rank = xm.get_ordinal()
283
+ xm.rendezvous("distributed_init") # wait for all workers
284
+
285
+ if is_master(cfg.distributed_training):
286
+ logging.getLogger().setLevel(logging.INFO)
287
+ else:
288
+ logging.getLogger().setLevel(logging.WARNING)
289
+
290
+ if cfg.common.model_parallel_size > 1:
291
+ try:
292
+ from fairseq.model_parallel.megatron.mpu import (
293
+ initialize_model_parallel,
294
+ model_parallel_cuda_manual_seed,
295
+ )
296
+ except ImportError:
297
+ raise ImportError(
298
+ "\n\nPlease install the megatron submodule:"
299
+ "\n\n git submodule update --init "
300
+ "fairseq/model_parallel/megatron"
301
+ )
302
+ global _USE_MEGATRON
303
+ _USE_MEGATRON = True
304
+ initialize_model_parallel(cfg.common.model_parallel_size)
305
+ model_parallel_cuda_manual_seed(cfg.common.seed)
306
+ model_part_number = get_model_parallel_rank()
307
+ cfg.checkpoint.checkpoint_suffix += "-model_part-{0}".format(model_part_number)
308
+
309
+ if hasattr(cfg, "model") and getattr(cfg.model, "base_layers", 0) > 0:
310
+ cfg.checkpoint.checkpoint_suffix = f"-rank-{cfg.distributed_training.distributed_rank}"
311
+
312
+ return cfg.distributed_training.distributed_rank
313
+
314
+
315
+ def distributed_main(i, main, cfg: FairseqConfig, kwargs):
316
+ cfg.distributed_training.device_id = i
317
+ if torch.cuda.is_available() and not cfg.common.cpu and not cfg.common.tpu:
318
+ torch.cuda.set_device(cfg.distributed_training.device_id)
319
+ if cfg.distributed_training.distributed_rank is None: # torch.multiprocessing.spawn
320
+ cfg.distributed_training.distributed_rank = kwargs.pop("start_rank", 0) + i
321
+
322
+ cfg.distributed_training.distributed_rank = distributed_init(cfg)
323
+
324
+ after_distributed_init_fn = kwargs.pop("after_distributed_init_fn", None)
325
+ if after_distributed_init_fn:
326
+ cfg = after_distributed_init_fn(cfg)
327
+
328
+ main(cfg, **kwargs)
329
+
330
+ if torch.distributed.is_initialized():
331
+ torch.distributed.barrier(get_global_group())
332
+
333
+
334
+ def call_main(cfg: FairseqConfig, main, **kwargs):
335
+ if cfg.distributed_training.distributed_init_method is None:
336
+ infer_init_method(cfg.distributed_training)
337
+
338
+ if cfg.distributed_training.distributed_init_method is not None:
339
+ # distributed training
340
+ if not cfg.distributed_training.distributed_no_spawn:
341
+ start_rank = cfg.distributed_training.distributed_rank
342
+ cfg.distributed_training.distributed_rank = None # assign automatically
343
+ kwargs["start_rank"] = start_rank
344
+ torch.multiprocessing.spawn(
345
+ fn=distributed_main,
346
+ args=(main, cfg, kwargs),
347
+ nprocs=min(
348
+ torch.cuda.device_count(),
349
+ cfg.distributed_training.distributed_world_size,
350
+ ),
351
+ join=True,
352
+ )
353
+ else:
354
+ distributed_main(cfg.distributed_training.device_id, main, cfg, kwargs)
355
+ elif cfg.common.tpu and cfg.distributed_training.distributed_world_size > 1:
356
+ import torch_xla.distributed.xla_multiprocessing as xmp
357
+
358
+ torch.multiprocessing.set_sharing_strategy("file_system")
359
+ xmp.spawn(
360
+ fn=distributed_main,
361
+ args=(main, cfg, kwargs),
362
+ # tpu-comment:
363
+ # 8 devices in one TPU VM, is the max processes to be spawned.
364
+ # The rest is driven by xm.distributed.xla_dist
365
+ nprocs=min(cfg.distributed_training.distributed_world_size, 8),
366
+ )
367
+ else:
368
+ # single GPU main
369
+ main(cfg, **kwargs)
370
+
371
+
372
+ def use_xla():
373
+ global _USE_XLA
374
+ return _USE_XLA
375
+
376
+
377
+ def new_groups(grouped_ranks: List[List[int]]):
378
+ if use_xla():
379
+ return ("tpu", grouped_ranks)
380
+ else:
381
+ groups = [dist.new_group(g) for g in grouped_ranks]
382
+ my_group_idx = _find_my_group_index(grouped_ranks)
383
+ return groups[my_group_idx]
384
+
385
+
386
+ def _find_my_group_index(grouped_ranks):
387
+ my_rank = get_global_rank()
388
+ for i, group in enumerate(grouped_ranks):
389
+ if my_rank in group:
390
+ return i
391
+ raise RuntimeError
392
+
393
+
394
+ def _find_my_group(grouped_ranks):
395
+ index = _find_my_group_index(grouped_ranks)
396
+ return grouped_ranks[index]
397
+
398
+
399
+ def get_rank(group):
400
+ if use_xla():
401
+ assert group[0] == "tpu"
402
+ my_group = _find_my_group(group[1])
403
+ return my_group.index(get_global_rank())
404
+ else:
405
+ return dist.get_rank(group=group)
406
+
407
+
408
+ def get_world_size(group):
409
+ if use_xla():
410
+ assert group[0] == "tpu"
411
+ my_group = _find_my_group(group[1])
412
+ return len(my_group)
413
+ elif torch.distributed.is_initialized():
414
+ return dist.get_world_size(group=group)
415
+ else:
416
+ return 1
417
+
418
+
419
+ def get_global_group():
420
+ if use_xla():
421
+ return new_groups([list(range(get_global_world_size()))])
422
+ elif torch.distributed.is_initialized():
423
+ if not hasattr(get_global_group, "_global_group"):
424
+ # ideally we could use torch.distributed.group.WORLD, but it seems
425
+ # to cause random NCCL hangs in some cases
426
+ get_global_group._global_group = dist.new_group()
427
+ return get_global_group._global_group
428
+ else:
429
+ return None
430
+
431
+
432
+ def get_global_rank():
433
+ if use_xla():
434
+ return xm.get_ordinal()
435
+ elif torch.distributed.is_initialized():
436
+ return torch.distributed.get_rank()
437
+ else:
438
+ return 0
439
+
440
+
441
+ def get_global_world_size():
442
+ if use_xla():
443
+ return xm.xrt_world_size()
444
+ elif torch.distributed.is_initialized():
445
+ return torch.distributed.get_world_size()
446
+ else:
447
+ return 1
448
+
449
+
450
+ def get_data_parallel_group():
451
+ """Get the data parallel group the caller rank belongs to."""
452
+ global _USE_MEGATRON
453
+ if _USE_MEGATRON:
454
+ from fairseq.model_parallel.megatron import mpu
455
+
456
+ return mpu.get_data_parallel_group()
457
+ else:
458
+ return get_global_group()
459
+
460
+
461
+ def get_data_parallel_rank():
462
+ """Return my rank for the data parallel group."""
463
+ return get_rank(get_data_parallel_group())
464
+
465
+
466
+ def get_data_parallel_world_size():
467
+ """Return world size for the data parallel group."""
468
+ return get_world_size(get_data_parallel_group())
469
+
470
+
471
+ def get_model_parallel_group():
472
+ global _USE_MEGATRON
473
+ if _USE_MEGATRON:
474
+ from fairseq.model_parallel.megatron import mpu
475
+
476
+ return mpu.get_model_parallel_group()
477
+ else:
478
+ return None
479
+
480
+
481
+ def get_model_parallel_rank():
482
+ """Return my rank for the model parallel group."""
483
+ return get_rank(get_model_parallel_group())
484
+
485
+
486
+ def get_model_parallel_world_size():
487
+ """Return world size for the model parallel group."""
488
+ return get_world_size(get_model_parallel_group())
489
+
490
+
491
+ def all_reduce(tensor, group, op="sum"):
492
+ if use_xla():
493
+ assert isinstance(group, tuple) and group[0] == "tpu"
494
+ tensor = [tensor] # wrap in a list to make xm.all_reduce in-place
495
+ return xm.all_reduce(op, tensor, groups=group[1])[0]
496
+ else:
497
+ if op == "sum":
498
+ op = dist.ReduceOp.SUM
499
+ elif op == "max":
500
+ op = dist.ReduceOp.MAX
501
+ else:
502
+ raise NotImplementedError
503
+ dist.all_reduce(tensor, op=op, group=group)
504
+ return tensor
505
+
506
+
507
+ def broadcast(tensor, src, group):
508
+ if use_xla():
509
+ # XLA doesn't support broadcast, hack it with all_reduce
510
+ if get_rank(group) != src:
511
+ tensor.zero_()
512
+ all_reduce(tensor, group)
513
+ else:
514
+ dist.broadcast(tensor, src=src, group=group)
515
+
516
+
517
+ def all_to_all(tensor, group):
518
+ """Perform an all-to-all operation on a 1D Tensor."""
519
+ assert tensor.dim() == 1
520
+ split_count = get_world_size(group=group)
521
+ assert tensor.numel() % split_count == 0
522
+ if use_xla():
523
+ assert isinstance(group, tuple) and group[0] == "tpu"
524
+ return xm.all_to_all(
525
+ tensor,
526
+ split_dimension=0,
527
+ concat_dimension=0,
528
+ split_count=split_count,
529
+ groups=group[1],
530
+ )
531
+ else:
532
+ output = torch.zeros_like(tensor)
533
+ dist.all_to_all_single(output, tensor, group=group)
534
+ return output
535
+
536
+
537
+ def all_gather(tensor, group, return_tensor=False):
538
+ """Perform an all-gather operation."""
539
+ if use_xla():
540
+ result = xm.all_gather(tensor, groups=group[1])
541
+ world_size = get_world_size(group=group)
542
+ result = result.view(world_size, *tensor.size())
543
+ if return_tensor:
544
+ return result
545
+ else:
546
+ return [result[i] for i in range(world_size)]
547
+ else:
548
+ world_size = get_world_size(group=group)
549
+ rank = get_rank(group=group)
550
+ tensor_list = [
551
+ tensor if i == rank else torch.empty_like(tensor) for i in range(world_size)
552
+ ]
553
+ dist.all_gather(tensor_list, tensor, group=group)
554
+ if return_tensor:
555
+ return torch.stack(tensor_list, dim=0)
556
+ else:
557
+ return tensor_list
558
+
559
+
560
+ def all_gather_list(data, group=None, max_size=16384):
561
+ """Gathers arbitrary data from all nodes into a list.
562
+
563
+ Similar to :func:`~torch.distributed.all_gather` but for arbitrary Python
564
+ data. Note that *data* must be picklable and any CUDA tensors will be moved
565
+ to CPU and returned on CPU as well.
566
+
567
+ Args:
568
+ data (Any): data from the local worker to be gathered on other workers
569
+ group: group of the collective
570
+ max_size (int, optional): maximum size of the data to be gathered
571
+ across workers
572
+ """
573
+ from fairseq import utils
574
+
575
+ if group is None:
576
+ group = get_global_group()
577
+ rank = get_rank(group=group)
578
+ world_size = get_world_size(group=group)
579
+
580
+ buffer_size = max_size * world_size
581
+ if (
582
+ not hasattr(all_gather_list, "_buffer")
583
+ or all_gather_list._buffer.numel() < buffer_size
584
+ ):
585
+ all_gather_list._buffer = torch.cuda.ByteTensor(buffer_size)
586
+ all_gather_list._cpu_buffer = torch.ByteTensor(max_size).pin_memory()
587
+ buffer = all_gather_list._buffer
588
+ buffer.zero_()
589
+ cpu_buffer = all_gather_list._cpu_buffer
590
+
591
+ data = utils.move_to_cpu(data)
592
+ enc = pickle.dumps(data)
593
+ enc_size = len(enc)
594
+ header_size = 4 # size of header that contains the length of the encoded data
595
+ size = header_size + enc_size
596
+ if size > max_size:
597
+ raise ValueError(
598
+ "encoded data size ({}) exceeds max_size ({})".format(size, max_size)
599
+ )
600
+
601
+ header = struct.pack(">I", enc_size)
602
+ cpu_buffer[:size] = torch.ByteTensor(list(header + enc))
603
+ start = rank * max_size
604
+ buffer[start : start + size].copy_(cpu_buffer[:size])
605
+
606
+ all_reduce(buffer, group=group)
607
+
608
+ buffer = buffer.cpu()
609
+ try:
610
+ result = []
611
+ for i in range(world_size):
612
+ out_buffer = buffer[i * max_size : (i + 1) * max_size]
613
+ (enc_size,) = struct.unpack(">I", bytes(out_buffer[:header_size].tolist()))
614
+ if enc_size > 0:
615
+ result.append(
616
+ pickle.loads(
617
+ bytes(out_buffer[header_size : header_size + enc_size].tolist())
618
+ )
619
+ )
620
+ return result
621
+ except pickle.UnpicklingError:
622
+ raise Exception(
623
+ "Unable to unpickle data from other workers. all_gather_list requires all "
624
+ "workers to enter the function together, so this error usually indicates "
625
+ "that the workers have fallen out of sync somehow. Workers can fall out of "
626
+ "sync if one of them runs out of memory, or if there are other conditions "
627
+ "in your training script that can cause one worker to finish an epoch "
628
+ "while other workers are still iterating over their portions of the data. "
629
+ "Try rerunning with --ddp-backend=legacy_ddp and see if that helps."
630
+ )
631
+
632
+
633
+ def all_reduce_dict(data: Mapping[str, Any], device, group) -> Dict[str, Any]:
634
+ """
635
+ AllReduce a dictionary of values across workers. We separately
636
+ reduce items that are already on the device and items on CPU for
637
+ better performance.
638
+
639
+ Args:
640
+ data (Mapping[str, Any]): dictionary of data to all-reduce, but
641
+ cannot be a nested dictionary
642
+ device (torch.device): device for the reduction
643
+ group: group of the collective
644
+ """
645
+ data_keys = list(data.keys())
646
+
647
+ # We want to separately reduce items that are already on the
648
+ # device and items on CPU for performance reasons.
649
+ cpu_data = OrderedDict()
650
+ device_data = OrderedDict()
651
+ for k in data_keys:
652
+ t = data[k]
653
+ if not torch.is_tensor(t):
654
+ cpu_data[k] = torch.tensor(t, dtype=torch.double)
655
+ elif t.device.type != device.type:
656
+ cpu_data[k] = t.to(dtype=torch.double)
657
+ else:
658
+ device_data[k] = t.to(dtype=torch.double)
659
+
660
+ def _all_reduce_dict(data: OrderedDict):
661
+ if len(data) == 0:
662
+ return data
663
+ buf = torch.cat([t.view(-1) for t in data.values()]).to(device=device)
664
+ all_reduce(buf, group=group)
665
+ split_buf = torch.split(buf, [t.numel() for t in data.values()])
666
+ reduced_data = [t.view_as(orig) for t, orig in zip(split_buf, data.values())]
667
+ return OrderedDict(zip(data.keys(), reduced_data))
668
+
669
+ cpu_data = _all_reduce_dict(cpu_data)
670
+ device_data = _all_reduce_dict(device_data)
671
+
672
+ def get_from_stack(key):
673
+ if key in cpu_data:
674
+ return cpu_data[key]
675
+ elif key in device_data:
676
+ return device_data[key]
677
+ raise KeyError
678
+
679
+ return OrderedDict([(key, get_from_stack(key)) for key in data_keys])
680
+
681
+
682
+ def broadcast_tensors(
683
+ tensors: Optional[List[torch.Tensor]],
684
+ src_rank: int,
685
+ group: object,
686
+ dist_device: Optional[torch.device] = None,
687
+ ) -> List[torch.Tensor]:
688
+ """
689
+ Broadcasts a list of tensors without other (non-src) ranks needing to know
690
+ the dtypes/shapes of the tensors.
691
+ """
692
+ if dist_device is None:
693
+ if torch.distributed.get_backend(group) == "nccl":
694
+ dist_device = torch.device("cuda")
695
+ else:
696
+ dist_device = torch.device("cpu")
697
+
698
+ # share metadata first to simplify transfer
699
+ is_src_rank = (get_rank(group) == src_rank)
700
+ if is_src_rank:
701
+ metadata = [
702
+ {"size": t.size(), "dtype": t.dtype, "device": t.device} for t in tensors
703
+ ]
704
+ metadata = _broadcast_object_slow(metadata, src_rank, group, dist_device)
705
+ else:
706
+ metadata = _broadcast_object_slow(None, src_rank, group, dist_device)
707
+
708
+ out_tensors = []
709
+ for i, meta in enumerate(metadata):
710
+ if is_src_rank:
711
+ tensor = tensors[i]
712
+ broadcast(tensors[i].to(dist_device), src=src_rank, group=group)
713
+ else:
714
+ tensor = torch.zeros(
715
+ [meta["size"].numel()], dtype=meta["dtype"], device=dist_device
716
+ )
717
+ broadcast(tensor, src=src_rank, group=group)
718
+ tensor = tensor.view(meta["size"]).to(meta["device"])
719
+ out_tensors.append(tensor)
720
+ return out_tensors
721
+
722
+
723
+ def broadcast_object(
724
+ obj: Any,
725
+ src_rank: int,
726
+ group: object,
727
+ dist_device: Optional[torch.device] = None,
728
+ ) -> Any:
729
+ """Broadcast an arbitrary Python object to other workers."""
730
+ if dist_device is None:
731
+ if torch.distributed.get_backend(group) == "nccl":
732
+ dist_device = torch.device("cuda")
733
+ else:
734
+ dist_device = torch.device("cpu")
735
+
736
+ if get_rank(group) == src_rank:
737
+ # split the tensors from the non-tensors so we can broadcast them
738
+ # directly, avoiding unnecessary serialization/deserialization
739
+ tensors = []
740
+ obj = _split_tensors_from_obj(obj, tensors)
741
+ obj = _broadcast_object_slow(obj, src_rank, group, dist_device)
742
+ tensors = broadcast_tensors(tensors, src_rank, group, dist_device)
743
+ else:
744
+ obj = _broadcast_object_slow(None, src_rank, group, dist_device)
745
+ tensors = broadcast_tensors(None, src_rank, group, dist_device)
746
+ return _put_tensors_in_obj(obj, tensors)
747
+
748
+
749
+ def _broadcast_object_slow(
750
+ obj: Any, src_rank: int, group: object, dist_device: torch.device,
751
+ ) -> Any:
752
+ if get_rank(group) == src_rank:
753
+ # Emit data
754
+ buffer = io.BytesIO()
755
+ torch.save(obj, buffer)
756
+ buffer = torch.ByteTensor(buffer.getbuffer()).to(dist_device)
757
+ length = torch.LongTensor([len(buffer)]).to(dist_device)
758
+ broadcast(length, src=src_rank, group=group)
759
+ broadcast(buffer, src=src_rank, group=group)
760
+ else:
761
+ # Fetch from the source
762
+ length = torch.LongTensor([0]).to(dist_device)
763
+ broadcast(length, src=src_rank, group=group)
764
+ buffer = torch.ByteTensor(int(length.item())).to(dist_device)
765
+ broadcast(buffer, src=src_rank, group=group)
766
+ buffer = io.BytesIO(buffer.cpu().numpy())
767
+ obj = torch.load(buffer, map_location="cpu")
768
+ return obj
769
+
770
+
771
+ @dataclass(frozen=True)
772
+ class _TensorPlaceholder:
773
+ index: int
774
+
775
+
776
+ def _split_tensors_from_obj(obj: Any, tensors: List[torch.Tensor]) -> Any:
777
+ if torch.is_tensor(obj):
778
+ placeholder = _TensorPlaceholder(index=len(tensors))
779
+ tensors.append(obj)
780
+ return placeholder
781
+ elif isinstance(obj, dict):
782
+ return {k: _split_tensors_from_obj(v, tensors) for k, v in obj.items()}
783
+ elif isinstance(obj, list):
784
+ return [_split_tensors_from_obj(v, tensors) for v in obj]
785
+ elif isinstance(obj, tuple):
786
+ return tuple(_split_tensors_from_obj(v, tensors) for v in obj)
787
+ elif isinstance(obj, set):
788
+ return {_split_tensors_from_obj(v, tensors) for v in obj}
789
+ else:
790
+ return obj
791
+
792
+
793
+ def _put_tensors_in_obj(obj: Any, tensors: List[torch.Tensor]) -> Any:
794
+ if isinstance(obj, _TensorPlaceholder):
795
+ return tensors[obj.index]
796
+ elif isinstance(obj, dict):
797
+ return {k: _put_tensors_in_obj(v, tensors) for k, v in obj.items()}
798
+ elif isinstance(obj, list):
799
+ return [_put_tensors_in_obj(v, tensors) for v in obj]
800
+ elif isinstance(obj, tuple):
801
+ return tuple(_put_tensors_in_obj(v, tensors) for v in obj)
802
+ elif isinstance(obj, set):
803
+ return {_put_tensors_in_obj(v, tensors) for v in obj}
804
+ else:
805
+ return obj
avh-align_core/fairseq/logging/__init__.py ADDED
File without changes
avh-align_core/fairseq/logging/meters.py ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import bisect
7
+ import time
8
+ from collections import OrderedDict
9
+ from typing import Dict, Optional
10
+
11
+
12
+ try:
13
+ import torch
14
+
15
+ def type_as(a, b):
16
+ if torch.is_tensor(a) and torch.is_tensor(b):
17
+ return a.to(b)
18
+ else:
19
+ return a
20
+
21
+
22
+ except ImportError:
23
+ torch = None
24
+
25
+ def type_as(a, b):
26
+ return a
27
+
28
+
29
+ try:
30
+ import numpy as np
31
+ except ImportError:
32
+ np = None
33
+
34
+
35
+ class Meter(object):
36
+ """Base class for Meters."""
37
+
38
+ def __init__(self):
39
+ pass
40
+
41
+ def state_dict(self):
42
+ return {}
43
+
44
+ def load_state_dict(self, state_dict):
45
+ pass
46
+
47
+ def reset(self):
48
+ raise NotImplementedError
49
+
50
+ @property
51
+ def smoothed_value(self) -> float:
52
+ """Smoothed value used for logging."""
53
+ raise NotImplementedError
54
+
55
+
56
+ def safe_round(number, ndigits):
57
+ if hasattr(number, "__round__"):
58
+ return round(number, ndigits)
59
+ elif torch is not None and torch.is_tensor(number) and number.numel() == 1:
60
+ return safe_round(number.item(), ndigits)
61
+ elif np is not None and np.ndim(number) == 0 and hasattr(number, "item"):
62
+ return safe_round(number.item(), ndigits)
63
+ else:
64
+ return number
65
+
66
+
67
+ class AverageMeter(Meter):
68
+ """Computes and stores the average and current value"""
69
+
70
+ def __init__(self, round: Optional[int] = None):
71
+ self.round = round
72
+ self.reset()
73
+
74
+ def reset(self):
75
+ self.val = None # most recent update
76
+ self.sum = 0 # sum from all updates
77
+ self.count = 0 # total n from all updates
78
+
79
+ def update(self, val, n=1):
80
+ if val is not None:
81
+ self.val = val
82
+ if n > 0:
83
+ self.sum = type_as(self.sum, val) + (val * n)
84
+ self.count = type_as(self.count, n) + n
85
+
86
+ def state_dict(self):
87
+ return {
88
+ "val": self.val,
89
+ "sum": self.sum,
90
+ "count": self.count,
91
+ "round": self.round,
92
+ }
93
+
94
+ def load_state_dict(self, state_dict):
95
+ self.val = state_dict["val"]
96
+ self.sum = state_dict["sum"]
97
+ self.count = state_dict["count"]
98
+ self.round = state_dict.get("round", None)
99
+
100
+ @property
101
+ def avg(self):
102
+ return self.sum / self.count if self.count > 0 else self.val
103
+
104
+ @property
105
+ def smoothed_value(self) -> float:
106
+ val = self.avg
107
+ if self.round is not None and val is not None:
108
+ val = safe_round(val, self.round)
109
+ return val
110
+
111
+
112
+ class SumMeter(Meter):
113
+ """Computes and stores the sum"""
114
+
115
+ def __init__(self, round: Optional[int] = None):
116
+ self.round = round
117
+ self.reset()
118
+
119
+ def reset(self):
120
+ self.sum = 0 # sum from all updates
121
+
122
+ def update(self, val):
123
+ if val is not None:
124
+ self.sum = type_as(self.sum, val) + val
125
+
126
+ def state_dict(self):
127
+ return {
128
+ "sum": self.sum,
129
+ "round": self.round,
130
+ }
131
+
132
+ def load_state_dict(self, state_dict):
133
+ self.sum = state_dict["sum"]
134
+ self.round = state_dict.get("round", None)
135
+
136
+ @property
137
+ def smoothed_value(self) -> float:
138
+ val = self.sum
139
+ if self.round is not None and val is not None:
140
+ val = safe_round(val, self.round)
141
+ return val
142
+
143
+
144
+ class TimeMeter(Meter):
145
+ """Computes the average occurrence of some event per second"""
146
+
147
+ def __init__(
148
+ self,
149
+ init: int = 0,
150
+ n: int = 0,
151
+ round: Optional[int] = None,
152
+ ):
153
+ self.round = round
154
+ self.reset(init, n)
155
+
156
+ def reset(self, init=0, n=0):
157
+ self.init = init
158
+ self.start = time.perf_counter()
159
+ self.n = n
160
+ self.i = 0
161
+
162
+ def update(self, val=1):
163
+ self.n = type_as(self.n, val) + val
164
+ self.i += 1
165
+
166
+ def state_dict(self):
167
+ return {
168
+ "init": self.elapsed_time,
169
+ "n": self.n,
170
+ "round": self.round,
171
+ }
172
+
173
+ def load_state_dict(self, state_dict):
174
+ if "start" in state_dict:
175
+ # backwards compatibility for old state_dicts
176
+ self.reset(init=state_dict["init"])
177
+ else:
178
+ self.reset(init=state_dict["init"], n=state_dict["n"])
179
+ self.round = state_dict.get("round", None)
180
+
181
+ @property
182
+ def avg(self):
183
+ return self.n / self.elapsed_time
184
+
185
+ @property
186
+ def elapsed_time(self):
187
+ return self.init + (time.perf_counter() - self.start)
188
+
189
+ @property
190
+ def smoothed_value(self) -> float:
191
+ val = self.avg
192
+ if self.round is not None and val is not None:
193
+ val = safe_round(val, self.round)
194
+ return val
195
+
196
+
197
+ class StopwatchMeter(Meter):
198
+ """Computes the sum/avg duration of some event in seconds"""
199
+
200
+ def __init__(self, round: Optional[int] = None):
201
+ self.round = round
202
+ self.sum = 0
203
+ self.n = 0
204
+ self.start_time = None
205
+
206
+ def start(self):
207
+ self.start_time = time.perf_counter()
208
+
209
+ def stop(self, n=1, prehook=None):
210
+ if self.start_time is not None:
211
+ if prehook is not None:
212
+ prehook()
213
+ delta = time.perf_counter() - self.start_time
214
+ self.sum = self.sum + delta
215
+ self.n = type_as(self.n, n) + n
216
+
217
+ def reset(self):
218
+ self.sum = 0 # cumulative time during which stopwatch was active
219
+ self.n = 0 # total n across all start/stop
220
+ self.start()
221
+
222
+ def state_dict(self):
223
+ return {
224
+ "sum": self.sum,
225
+ "n": self.n,
226
+ "round": self.round,
227
+ }
228
+
229
+ def load_state_dict(self, state_dict):
230
+ self.sum = state_dict["sum"]
231
+ self.n = state_dict["n"]
232
+ self.start_time = None
233
+ self.round = state_dict.get("round", None)
234
+
235
+ @property
236
+ def avg(self):
237
+ return self.sum / self.n if self.n > 0 else self.sum
238
+
239
+ @property
240
+ def elapsed_time(self):
241
+ if self.start_time is None:
242
+ return 0.0
243
+ return time.perf_counter() - self.start_time
244
+
245
+ @property
246
+ def smoothed_value(self) -> float:
247
+ val = self.avg if self.sum > 0 else self.elapsed_time
248
+ if self.round is not None and val is not None:
249
+ val = safe_round(val, self.round)
250
+ return val
251
+
252
+
253
+ class MetersDict(OrderedDict):
254
+ """A sorted dictionary of :class:`Meters`.
255
+
256
+ Meters are sorted according to a priority that is given when the
257
+ meter is first added to the dictionary.
258
+ """
259
+
260
+ def __init__(self, *args, **kwargs):
261
+ super().__init__(*args, **kwargs)
262
+ self.priorities = []
263
+
264
+ def __setitem__(self, key, value):
265
+ assert key not in self, "MetersDict doesn't support reassignment"
266
+ priority, value = value
267
+ bisect.insort(self.priorities, (priority, len(self.priorities), key))
268
+ super().__setitem__(key, value)
269
+ for _, _, key in self.priorities: # reorder dict to match priorities
270
+ self.move_to_end(key)
271
+
272
+ def add_meter(self, key, meter, priority):
273
+ self.__setitem__(key, (priority, meter))
274
+
275
+ def state_dict(self):
276
+ return [
277
+ (pri, key, self[key].__class__.__name__, self[key].state_dict())
278
+ for pri, _, key in self.priorities
279
+ # can't serialize DerivedMeter instances
280
+ if not isinstance(self[key], MetersDict._DerivedMeter)
281
+ ]
282
+
283
+ def load_state_dict(self, state_dict):
284
+ self.clear()
285
+ self.priorities.clear()
286
+ for pri, key, meter_cls, meter_state in state_dict:
287
+ meter = globals()[meter_cls]()
288
+ meter.load_state_dict(meter_state)
289
+ self.add_meter(key, meter, pri)
290
+
291
+ def get_smoothed_value(self, key: str) -> float:
292
+ """Get a single smoothed value."""
293
+ meter = self[key]
294
+ if isinstance(meter, MetersDict._DerivedMeter):
295
+ return meter.fn(self)
296
+ else:
297
+ return meter.smoothed_value
298
+
299
+ def get_smoothed_values(self) -> Dict[str, float]:
300
+ """Get all smoothed values."""
301
+ return OrderedDict(
302
+ [
303
+ (key, self.get_smoothed_value(key))
304
+ for key in self.keys()
305
+ if not key.startswith("_")
306
+ ]
307
+ )
308
+
309
+ def reset(self):
310
+ """Reset Meter instances."""
311
+ for meter in self.values():
312
+ if isinstance(meter, MetersDict._DerivedMeter):
313
+ continue
314
+ meter.reset()
315
+
316
+ class _DerivedMeter(Meter):
317
+ """A Meter whose values are derived from other Meters."""
318
+
319
+ def __init__(self, fn):
320
+ self.fn = fn
321
+
322
+ def reset(self):
323
+ pass
avh-align_core/fairseq/logging/metrics.py ADDED
@@ -0,0 +1,314 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+ """
6
+ A standalone module for aggregating metrics.
7
+
8
+ Metrics can be logged from anywhere using the `log_*` functions defined
9
+ in this module. The logged values will be aggregated dynamically based
10
+ on the aggregation context in which the logging occurs. See the
11
+ :func:`aggregate` context manager for more details.
12
+ """
13
+
14
+ import contextlib
15
+ import uuid
16
+ from collections import defaultdict
17
+ from typing import Callable, List, Optional
18
+
19
+ from .meters import *
20
+
21
+
22
+ # Aggregation contexts are considered "active" when inside the scope
23
+ # created by the :func:`aggregate` context manager.
24
+ _aggregators = OrderedDict()
25
+ _active_aggregators = OrderedDict()
26
+ _active_aggregators_cnt = defaultdict(lambda: 0)
27
+
28
+
29
+ def reset() -> None:
30
+ """Reset all metrics aggregators."""
31
+ _aggregators.clear()
32
+ _active_aggregators.clear()
33
+ _active_aggregators_cnt.clear()
34
+
35
+ # The "default" aggregator observes all logged values.
36
+ _aggregators["default"] = MetersDict()
37
+ _active_aggregators["default"] = _aggregators["default"]
38
+ _active_aggregators_cnt["default"] = 1
39
+
40
+
41
+ reset()
42
+
43
+
44
+ @contextlib.contextmanager
45
+ def aggregate(name: Optional[str] = None, new_root: bool = False):
46
+ """Context manager to aggregate metrics under a given name.
47
+
48
+ Aggregations can be nested. If *new_root* is ``False``, then logged
49
+ metrics will be recorded along the entire stack of nested
50
+ aggregators, including a global "default" aggregator. If *new_root*
51
+ is ``True``, then this aggregator will be the root of a new
52
+ aggregation stack, thus bypassing any parent aggregators.
53
+
54
+ Note that aggregation contexts are uniquely identified by their
55
+ *name* (e.g., train, valid). Creating a context with an existing
56
+ name will reuse the corresponding :class:`MetersDict` instance.
57
+ If no name is given, then a temporary aggregator will be created.
58
+
59
+ Usage::
60
+
61
+ with metrics.aggregate("train"):
62
+ for step, batch in enumerate(epoch):
63
+ with metrics.aggregate("train_inner") as agg:
64
+ metrics.log_scalar("loss", get_loss(batch))
65
+ if step % log_interval == 0:
66
+ print(agg.get_smoothed_value("loss"))
67
+ agg.reset()
68
+ print(metrics.get_smoothed_values("train")["loss"])
69
+
70
+ Args:
71
+ name (str): name of the aggregation. Defaults to a
72
+ random/temporary name if not given explicitly.
73
+ new_root (bool): make this aggregation the root of a new
74
+ aggregation stack.
75
+ """
76
+ if name is None:
77
+ # generate a temporary name
78
+ name = str(uuid.uuid4())
79
+ assert name not in _aggregators
80
+ agg = MetersDict()
81
+ else:
82
+ assert name != "default"
83
+ agg = _aggregators.setdefault(name, MetersDict())
84
+
85
+ if new_root:
86
+ backup_aggregators = _active_aggregators.copy()
87
+ _active_aggregators.clear()
88
+ backup_aggregators_cnt = _active_aggregators_cnt.copy()
89
+ _active_aggregators_cnt.clear()
90
+
91
+ _active_aggregators[name] = agg
92
+ _active_aggregators_cnt[name] += 1
93
+
94
+ yield agg
95
+
96
+ _active_aggregators_cnt[name] -= 1
97
+ if _active_aggregators_cnt[name] == 0 and name in _active_aggregators:
98
+ del _active_aggregators[name]
99
+
100
+ if new_root:
101
+ _active_aggregators.clear()
102
+ _active_aggregators.update(backup_aggregators)
103
+ _active_aggregators_cnt.clear()
104
+ _active_aggregators_cnt.update(backup_aggregators_cnt)
105
+
106
+
107
+ def get_active_aggregators() -> List[MetersDict]:
108
+ return list(_active_aggregators.values())
109
+
110
+
111
+ def log_scalar(
112
+ key: str,
113
+ value: float,
114
+ weight: float = 1,
115
+ priority: int = 10,
116
+ round: Optional[int] = None,
117
+ ):
118
+ """Log a scalar value.
119
+
120
+ Args:
121
+ key (str): name of the field to log
122
+ value (float): value to log
123
+ weight (float): weight that this value contributes to the average.
124
+ A weight of 0 will always log the latest value.
125
+ priority (int): smaller values are logged earlier in the output
126
+ round (Optional[int]): number of digits to round to when displaying
127
+ """
128
+ for agg in get_active_aggregators():
129
+ if key not in agg:
130
+ agg.add_meter(key, AverageMeter(round=round), priority)
131
+ agg[key].update(value, weight)
132
+
133
+ def log_scalar_sum(
134
+ key: str,
135
+ value: float,
136
+ priority: int = 10,
137
+ round: Optional[int] = None,
138
+ ):
139
+ """Log a scalar value that is summed for reporting.
140
+
141
+ Args:
142
+ key (str): name of the field to log
143
+ value (float): value to log
144
+ priority (int): smaller values are logged earlier in the output
145
+ round (Optional[int]): number of digits to round to when displaying
146
+ """
147
+ for agg in get_active_aggregators():
148
+ if key not in agg:
149
+ agg.add_meter(key, SumMeter(round=round), priority)
150
+ agg[key].update(value)
151
+
152
+
153
+ def log_derived(key: str, fn: Callable[[MetersDict], float], priority: int = 20):
154
+ """Log a scalar value derived from other meters.
155
+
156
+ Args:
157
+ key (str): name of the field to log
158
+ fn (Callable[[MetersDict], float]): function that takes a single
159
+ argument *meters* and returns the derived value
160
+ priority (int): smaller values are logged earlier in the output
161
+ """
162
+ for agg in get_active_aggregators():
163
+ if key not in agg:
164
+ agg.add_meter(key, MetersDict._DerivedMeter(fn), priority)
165
+
166
+
167
+ def log_speed(
168
+ key: str,
169
+ value: float,
170
+ priority: int = 30,
171
+ round: Optional[int] = None,
172
+ ):
173
+ """Log the rate of some quantity per second.
174
+
175
+ Args:
176
+ key (str): name of the field to log
177
+ value (float): value to log
178
+ priority (int): smaller values are logged earlier in the output
179
+ round (Optional[int]): number of digits to round to when displaying
180
+ """
181
+ for agg in get_active_aggregators():
182
+ if key not in agg:
183
+ agg.add_meter(key, TimeMeter(round=round), priority)
184
+ agg[key].reset() # reset meter on the first call
185
+ else:
186
+ agg[key].update(value)
187
+
188
+
189
+ def log_start_time(key: str, priority: int = 40, round: Optional[int] = None):
190
+ """Log the duration of some event in seconds.
191
+
192
+ The duration will be computed once :func:`log_stop_time` is called.
193
+
194
+ Args:
195
+ key (str): name of the field to log
196
+ priority (int): smaller values are logged earlier in the output
197
+ round (Optional[int]): number of digits to round to when displaying
198
+ """
199
+ for agg in get_active_aggregators():
200
+ if key not in agg:
201
+ agg.add_meter(key, StopwatchMeter(round=round), priority)
202
+ agg[key].start()
203
+
204
+
205
+ def log_stop_time(key: str, weight: float = 0.0, prehook=None):
206
+ """Log the duration of some event in seconds.
207
+
208
+ The duration will be computed since :func:`log_start_time` was called.
209
+ Set weight > 0 to report the average time instead of the sum.
210
+
211
+ Args:
212
+ key (str): name of the field to log
213
+ weight (float): weight that this time contributes to the average
214
+ prehook (function, no arguments): will be called before the timer
215
+ is stopped. For example, use prehook=torch.cuda.synchronize to
216
+ make sure all gpu operations are done before timer is stopped.
217
+ """
218
+ for agg in get_active_aggregators():
219
+ if key in agg:
220
+ agg[key].stop(weight, prehook)
221
+
222
+
223
+ def log_custom(
224
+ new_meter_fn: Callable[[], Meter],
225
+ key: str,
226
+ *args,
227
+ priority: int = 50,
228
+ **kwargs,
229
+ ):
230
+ """Log using a custom Meter.
231
+
232
+ Any extra *args* or *kwargs* will be passed through to the Meter's
233
+ *update* method.
234
+
235
+ Args:
236
+ new_meter_fn (Callable[[], Meter]): function that returns a new
237
+ Meter instance
238
+ key (str): name of the field to log
239
+ priority (int): smaller values are logged earlier in the output
240
+ """
241
+ for agg in get_active_aggregators():
242
+ if key not in agg:
243
+ agg.add_meter(key, new_meter_fn(), priority)
244
+ agg[key].update(*args, **kwargs)
245
+
246
+
247
+ def reset_meter(name: str, key: str) -> None:
248
+ """Reset Meter instance aggregated under a given *name* and *key*."""
249
+ meter = get_meter(name, key)
250
+ if meter is not None:
251
+ meter.reset()
252
+
253
+
254
+ def reset_meters(name: str) -> None:
255
+ """Reset Meter instances aggregated under a given *name*."""
256
+ meters = get_meters(name)
257
+ if meters is not None:
258
+ meters.reset()
259
+
260
+
261
+ def get_meter(name: str, key: str) -> Meter:
262
+ """Get a single Meter instance aggregated under *name* and *key*.
263
+
264
+ Returns:
265
+ Meter or None if no metrics have been logged under *name* and *key*.
266
+ """
267
+ if name not in _aggregators:
268
+ return None
269
+ return _aggregators[name].get(key, None)
270
+
271
+
272
+ def get_meters(name: str) -> MetersDict:
273
+ """Get Meter instances aggregated under a given *name*.
274
+
275
+ Returns:
276
+ MetersDict or None if no metrics have been logged under *name*.
277
+ """
278
+ return _aggregators.get(name, None)
279
+
280
+
281
+ def get_smoothed_value(name: str, key: str) -> float:
282
+ """Get a single smoothed value.
283
+
284
+ Raises:
285
+ KeyError: if no metrics have been logged under *name* and *key*.
286
+ """
287
+ return _aggregators[name].get_smoothed_value(key)
288
+
289
+
290
+ def get_smoothed_values(name: str) -> Dict[str, float]:
291
+ """Get smoothed values aggregated under a given *name*.
292
+
293
+ Raises:
294
+ KeyError: if no metrics have been logged under *name*.
295
+ """
296
+ return _aggregators[name].get_smoothed_values()
297
+
298
+
299
+ def state_dict():
300
+ return OrderedDict([(name, agg.state_dict()) for name, agg in _aggregators.items()])
301
+
302
+
303
+ def load_state_dict(state_dict):
304
+ for name, agg_state in state_dict.items():
305
+ _aggregators[name] = MetersDict()
306
+ _aggregators[name].load_state_dict(agg_state)
307
+
308
+
309
+ def xla_metrics_report():
310
+ try:
311
+ import torch_xla.debug.metrics as met
312
+ print(met.metrics_report())
313
+ except ImportError:
314
+ return
avh-align_core/fairseq/logging/progress_bar.py ADDED
@@ -0,0 +1,490 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ """
7
+ Wrapper around various loggers and progress bars (e.g., tqdm).
8
+ """
9
+
10
+ import atexit
11
+ import json
12
+ import logging
13
+ import os
14
+ import sys
15
+ from collections import OrderedDict
16
+ from contextlib import contextmanager
17
+ from numbers import Number
18
+ from typing import Optional
19
+
20
+ import torch
21
+
22
+ from .meters import AverageMeter, StopwatchMeter, TimeMeter
23
+
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ def progress_bar(
29
+ iterator,
30
+ log_format: Optional[str] = None,
31
+ log_interval: int = 100,
32
+ log_file: Optional[str] = None,
33
+ epoch: Optional[int] = None,
34
+ prefix: Optional[str] = None,
35
+ tensorboard_logdir: Optional[str] = None,
36
+ default_log_format: str = "tqdm",
37
+ wandb_project: Optional[str] = None,
38
+ wandb_run_name: Optional[str] = None,
39
+ azureml_logging: Optional[bool] = False,
40
+ ):
41
+ if log_format is None:
42
+ log_format = default_log_format
43
+ if log_file is not None:
44
+ handler = logging.FileHandler(filename=log_file)
45
+ logger.addHandler(handler)
46
+
47
+ if log_format == "tqdm" and not sys.stderr.isatty():
48
+ log_format = "simple"
49
+
50
+ if log_format == "json":
51
+ bar = JsonProgressBar(iterator, epoch, prefix, log_interval)
52
+ elif log_format == "none":
53
+ bar = NoopProgressBar(iterator, epoch, prefix)
54
+ elif log_format == "simple":
55
+ bar = SimpleProgressBar(iterator, epoch, prefix, log_interval)
56
+ elif log_format == "tqdm":
57
+ bar = TqdmProgressBar(iterator, epoch, prefix)
58
+ else:
59
+ raise ValueError("Unknown log format: {}".format(log_format))
60
+
61
+ if tensorboard_logdir:
62
+ try:
63
+ # [FB only] custom wrapper for TensorBoard
64
+ import palaas # noqa
65
+ from .fb_tbmf_wrapper import FbTbmfWrapper
66
+
67
+ bar = FbTbmfWrapper(bar, log_interval)
68
+ except ImportError:
69
+ bar = TensorboardProgressBarWrapper(bar, tensorboard_logdir)
70
+
71
+ if wandb_project:
72
+ bar = WandBProgressBarWrapper(bar, wandb_project, run_name=wandb_run_name)
73
+
74
+ if azureml_logging:
75
+ bar = AzureMLProgressBarWrapper(bar)
76
+
77
+ return bar
78
+
79
+
80
+ def build_progress_bar(
81
+ args,
82
+ iterator,
83
+ epoch: Optional[int] = None,
84
+ prefix: Optional[str] = None,
85
+ default: str = "tqdm",
86
+ no_progress_bar: str = "none",
87
+ ):
88
+ """Legacy wrapper that takes an argparse.Namespace."""
89
+ if getattr(args, "no_progress_bar", False):
90
+ default = no_progress_bar
91
+ if getattr(args, "distributed_rank", 0) == 0:
92
+ tensorboard_logdir = getattr(args, "tensorboard_logdir", None)
93
+ else:
94
+ tensorboard_logdir = None
95
+ return progress_bar(
96
+ iterator,
97
+ log_format=args.log_format,
98
+ log_interval=args.log_interval,
99
+ epoch=epoch,
100
+ prefix=prefix,
101
+ tensorboard_logdir=tensorboard_logdir,
102
+ default_log_format=default,
103
+ )
104
+
105
+
106
+ def format_stat(stat):
107
+ if isinstance(stat, Number):
108
+ stat = "{:g}".format(stat)
109
+ elif isinstance(stat, AverageMeter):
110
+ stat = "{:.3f}".format(stat.avg)
111
+ elif isinstance(stat, TimeMeter):
112
+ stat = "{:g}".format(round(stat.avg))
113
+ elif isinstance(stat, StopwatchMeter):
114
+ stat = "{:g}".format(round(stat.sum))
115
+ elif torch.is_tensor(stat):
116
+ stat = stat.tolist()
117
+ return stat
118
+
119
+
120
+ class BaseProgressBar(object):
121
+ """Abstract class for progress bars."""
122
+
123
+ def __init__(self, iterable, epoch=None, prefix=None):
124
+ self.iterable = iterable
125
+ self.n = getattr(iterable, "n", 0)
126
+ self.epoch = epoch
127
+ self.prefix = ""
128
+ if epoch is not None:
129
+ self.prefix += "epoch {:03d}".format(epoch)
130
+ if prefix is not None:
131
+ self.prefix += (" | " if self.prefix != "" else "") + prefix
132
+
133
+ def __len__(self):
134
+ return len(self.iterable)
135
+
136
+ def __enter__(self):
137
+ return self
138
+
139
+ def __exit__(self, *exc):
140
+ return False
141
+
142
+ def __iter__(self):
143
+ raise NotImplementedError
144
+
145
+ def log(self, stats, tag=None, step=None):
146
+ """Log intermediate stats according to log_interval."""
147
+ raise NotImplementedError
148
+
149
+ def print(self, stats, tag=None, step=None):
150
+ """Print end-of-epoch stats."""
151
+ raise NotImplementedError
152
+
153
+ def update_config(self, config):
154
+ """Log latest configuration."""
155
+ pass
156
+
157
+ def _str_commas(self, stats):
158
+ return ", ".join(key + "=" + stats[key].strip() for key in stats.keys())
159
+
160
+ def _str_pipes(self, stats):
161
+ return " | ".join(key + " " + stats[key].strip() for key in stats.keys())
162
+
163
+ def _format_stats(self, stats):
164
+ postfix = OrderedDict(stats)
165
+ # Preprocess stats according to datatype
166
+ for key in postfix.keys():
167
+ postfix[key] = str(format_stat(postfix[key]))
168
+ return postfix
169
+
170
+
171
+ @contextmanager
172
+ def rename_logger(logger, new_name):
173
+ old_name = logger.name
174
+ if new_name is not None:
175
+ logger.name = new_name
176
+ yield logger
177
+ logger.name = old_name
178
+
179
+
180
+ class JsonProgressBar(BaseProgressBar):
181
+ """Log output in JSON format."""
182
+
183
+ def __init__(self, iterable, epoch=None, prefix=None, log_interval=1000):
184
+ super().__init__(iterable, epoch, prefix)
185
+ self.log_interval = log_interval
186
+ self.i = None
187
+ self.size = None
188
+
189
+ def __iter__(self):
190
+ self.size = len(self.iterable)
191
+ for i, obj in enumerate(self.iterable, start=self.n):
192
+ self.i = i
193
+ yield obj
194
+
195
+ def log(self, stats, tag=None, step=None):
196
+ """Log intermediate stats according to log_interval."""
197
+ step = step or self.i or 0
198
+ if step > 0 and self.log_interval is not None and step % self.log_interval == 0:
199
+ update = (
200
+ self.epoch - 1 + (self.i + 1) / float(self.size)
201
+ if self.epoch is not None
202
+ else None
203
+ )
204
+ stats = self._format_stats(stats, epoch=self.epoch, update=update)
205
+ with rename_logger(logger, tag):
206
+ logger.info(json.dumps(stats))
207
+
208
+ def print(self, stats, tag=None, step=None):
209
+ """Print end-of-epoch stats."""
210
+ self.stats = stats
211
+ if tag is not None:
212
+ self.stats = OrderedDict(
213
+ [(tag + "_" + k, v) for k, v in self.stats.items()]
214
+ )
215
+ stats = self._format_stats(self.stats, epoch=self.epoch)
216
+ with rename_logger(logger, tag):
217
+ logger.info(json.dumps(stats))
218
+
219
+ def _format_stats(self, stats, epoch=None, update=None):
220
+ postfix = OrderedDict()
221
+ if epoch is not None:
222
+ postfix["epoch"] = epoch
223
+ if update is not None:
224
+ postfix["update"] = round(update, 3)
225
+ # Preprocess stats according to datatype
226
+ for key in stats.keys():
227
+ postfix[key] = format_stat(stats[key])
228
+ return postfix
229
+
230
+
231
+ class NoopProgressBar(BaseProgressBar):
232
+ """No logging."""
233
+
234
+ def __init__(self, iterable, epoch=None, prefix=None):
235
+ super().__init__(iterable, epoch, prefix)
236
+
237
+ def __iter__(self):
238
+ for obj in self.iterable:
239
+ yield obj
240
+
241
+ def log(self, stats, tag=None, step=None):
242
+ """Log intermediate stats according to log_interval."""
243
+ pass
244
+
245
+ def print(self, stats, tag=None, step=None):
246
+ """Print end-of-epoch stats."""
247
+ pass
248
+
249
+
250
+ class SimpleProgressBar(BaseProgressBar):
251
+ """A minimal logger for non-TTY environments."""
252
+
253
+ def __init__(self, iterable, epoch=None, prefix=None, log_interval=1000):
254
+ super().__init__(iterable, epoch, prefix)
255
+ self.log_interval = log_interval
256
+ self.i = None
257
+ self.size = None
258
+
259
+ def __iter__(self):
260
+ self.size = len(self.iterable)
261
+ for i, obj in enumerate(self.iterable, start=self.n):
262
+ self.i = i
263
+ yield obj
264
+
265
+ def log(self, stats, tag=None, step=None):
266
+ """Log intermediate stats according to log_interval."""
267
+ step = step or self.i or 0
268
+ if step > 0 and self.log_interval is not None and step % self.log_interval == 0:
269
+ stats = self._format_stats(stats)
270
+ postfix = self._str_commas(stats)
271
+ with rename_logger(logger, tag):
272
+ logger.info(
273
+ "{}: {:5d} / {:d} {}".format(
274
+ self.prefix, self.i + 1, self.size, postfix
275
+ )
276
+ )
277
+
278
+ def print(self, stats, tag=None, step=None):
279
+ """Print end-of-epoch stats."""
280
+ postfix = self._str_pipes(self._format_stats(stats))
281
+ with rename_logger(logger, tag):
282
+ logger.info("{} | {}".format(self.prefix, postfix))
283
+
284
+
285
+ class TqdmProgressBar(BaseProgressBar):
286
+ """Log to tqdm."""
287
+
288
+ def __init__(self, iterable, epoch=None, prefix=None):
289
+ super().__init__(iterable, epoch, prefix)
290
+ from tqdm import tqdm
291
+
292
+ self.tqdm = tqdm(
293
+ iterable,
294
+ self.prefix,
295
+ leave=False,
296
+ disable=(logger.getEffectiveLevel() > logging.INFO),
297
+ )
298
+
299
+ def __iter__(self):
300
+ return iter(self.tqdm)
301
+
302
+ def log(self, stats, tag=None, step=None):
303
+ """Log intermediate stats according to log_interval."""
304
+ self.tqdm.set_postfix(self._format_stats(stats), refresh=False)
305
+
306
+ def print(self, stats, tag=None, step=None):
307
+ """Print end-of-epoch stats."""
308
+ postfix = self._str_pipes(self._format_stats(stats))
309
+ with rename_logger(logger, tag):
310
+ logger.info("{} | {}".format(self.prefix, postfix))
311
+
312
+
313
+ try:
314
+ _tensorboard_writers = {}
315
+ from torch.utils.tensorboard import SummaryWriter
316
+ except ImportError:
317
+ try:
318
+ from tensorboardX import SummaryWriter
319
+ except ImportError:
320
+ SummaryWriter = None
321
+
322
+
323
+ def _close_writers():
324
+ for w in _tensorboard_writers.values():
325
+ w.close()
326
+
327
+
328
+ atexit.register(_close_writers)
329
+
330
+
331
+ class TensorboardProgressBarWrapper(BaseProgressBar):
332
+ """Log to tensorboard."""
333
+
334
+ def __init__(self, wrapped_bar, tensorboard_logdir):
335
+ self.wrapped_bar = wrapped_bar
336
+ self.tensorboard_logdir = tensorboard_logdir
337
+
338
+ if SummaryWriter is None:
339
+ logger.warning(
340
+ "tensorboard not found, please install with: pip install tensorboard"
341
+ )
342
+
343
+ def _writer(self, key):
344
+ if SummaryWriter is None:
345
+ return None
346
+ _writers = _tensorboard_writers
347
+ if key not in _writers:
348
+ _writers[key] = SummaryWriter(os.path.join(self.tensorboard_logdir, key))
349
+ _writers[key].add_text("sys.argv", " ".join(sys.argv))
350
+ return _writers[key]
351
+
352
+ def __iter__(self):
353
+ return iter(self.wrapped_bar)
354
+
355
+ def log(self, stats, tag=None, step=None):
356
+ """Log intermediate stats to tensorboard."""
357
+ self._log_to_tensorboard(stats, tag, step)
358
+ self.wrapped_bar.log(stats, tag=tag, step=step)
359
+
360
+ def print(self, stats, tag=None, step=None):
361
+ """Print end-of-epoch stats."""
362
+ self._log_to_tensorboard(stats, tag, step)
363
+ self.wrapped_bar.print(stats, tag=tag, step=step)
364
+
365
+ def update_config(self, config):
366
+ """Log latest configuration."""
367
+ # TODO add hparams to Tensorboard
368
+ self.wrapped_bar.update_config(config)
369
+
370
+ def _log_to_tensorboard(self, stats, tag=None, step=None):
371
+ writer = self._writer(tag or "")
372
+ if writer is None:
373
+ return
374
+ if step is None:
375
+ step = stats["num_updates"]
376
+ for key in stats.keys() - {"num_updates"}:
377
+ if isinstance(stats[key], AverageMeter):
378
+ writer.add_scalar(key, stats[key].val, step)
379
+ elif isinstance(stats[key], Number):
380
+ writer.add_scalar(key, stats[key], step)
381
+ elif torch.is_tensor(stats[key]) and stats[key].numel() == 1:
382
+ writer.add_scalar(key, stats[key].item(), step)
383
+ writer.flush()
384
+
385
+
386
+ try:
387
+ import wandb
388
+ except ImportError:
389
+ wandb = None
390
+
391
+
392
+ class WandBProgressBarWrapper(BaseProgressBar):
393
+ """Log to Weights & Biases."""
394
+
395
+ def __init__(self, wrapped_bar, wandb_project, run_name=None):
396
+ self.wrapped_bar = wrapped_bar
397
+ if wandb is None:
398
+ logger.warning("wandb not found, pip install wandb")
399
+ return
400
+
401
+ # reinit=False to ensure if wandb.init() is called multiple times
402
+ # within one process it still references the same run
403
+ wandb.init(project=wandb_project, reinit=False, name=run_name)
404
+
405
+ def __iter__(self):
406
+ return iter(self.wrapped_bar)
407
+
408
+ def log(self, stats, tag=None, step=None):
409
+ """Log intermediate stats to tensorboard."""
410
+ self._log_to_wandb(stats, tag, step)
411
+ self.wrapped_bar.log(stats, tag=tag, step=step)
412
+
413
+ def print(self, stats, tag=None, step=None):
414
+ """Print end-of-epoch stats."""
415
+ self._log_to_wandb(stats, tag, step)
416
+ self.wrapped_bar.print(stats, tag=tag, step=step)
417
+
418
+ def update_config(self, config):
419
+ """Log latest configuration."""
420
+ if wandb is not None:
421
+ wandb.config.update(config)
422
+ self.wrapped_bar.update_config(config)
423
+
424
+ def _log_to_wandb(self, stats, tag=None, step=None):
425
+ if wandb is None:
426
+ return
427
+ if step is None:
428
+ step = stats["num_updates"]
429
+
430
+ prefix = "" if tag is None else tag + "/"
431
+
432
+ for key in stats.keys() - {"num_updates"}:
433
+ if isinstance(stats[key], AverageMeter):
434
+ wandb.log({prefix + key: stats[key].val}, step=step)
435
+ elif isinstance(stats[key], Number):
436
+ wandb.log({prefix + key: stats[key]}, step=step)
437
+
438
+
439
+ try:
440
+ from azureml.core import Run
441
+ except ImportError:
442
+ Run = None
443
+
444
+
445
+ class AzureMLProgressBarWrapper(BaseProgressBar):
446
+ """Log to Azure ML"""
447
+
448
+ def __init__(self, wrapped_bar):
449
+ self.wrapped_bar = wrapped_bar
450
+ if Run is None:
451
+ logger.warning("azureml.core not found, pip install azureml-core")
452
+ return
453
+ self.run = Run.get_context()
454
+
455
+ def __exit__(self, *exc):
456
+ if Run is not None:
457
+ self.run.complete()
458
+ return False
459
+
460
+ def __iter__(self):
461
+ return iter(self.wrapped_bar)
462
+
463
+ def log(self, stats, tag=None, step=None):
464
+ """Log intermediate stats to AzureML"""
465
+ self._log_to_azureml(stats, tag, step)
466
+ self.wrapped_bar.log(stats, tag=tag, step=step)
467
+
468
+ def print(self, stats, tag=None, step=None):
469
+ """Print end-of-epoch stats"""
470
+ self._log_to_azureml(stats, tag, step)
471
+ self.wrapped_bar.print(stats, tag=tag, step=step)
472
+
473
+ def update_config(self, config):
474
+ """Log latest configuration."""
475
+ self.wrapped_bar.update_config(config)
476
+
477
+ def _log_to_azureml(self, stats, tag=None, step=None):
478
+ if Run is None:
479
+ return
480
+ if step is None:
481
+ step = stats["num_updates"]
482
+
483
+ prefix = "" if tag is None else tag + "/"
484
+
485
+ for key in stats.keys() - {"num_updates"}:
486
+ name = prefix + key
487
+ if isinstance(stats[key], AverageMeter):
488
+ self.run.log_row(name=name, **{"step": step, key: stats[key].val})
489
+ elif isinstance(stats[key], Number):
490
+ self.run.log_row(name=name, **{"step": step, key: stats[key]})
avh-align_core/fairseq/model_parallel/criterions/__init__.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import importlib
7
+ import os
8
+
9
+
10
+ # automatically import any Python files in the criterions/ directory
11
+ for file in sorted(os.listdir(os.path.dirname(__file__))):
12
+ if file.endswith(".py") and not file.startswith("_"):
13
+ module = file[: file.find(".py")]
14
+ importlib.import_module("fairseq.model_parallel.criterions." + module)
avh-align_core/fairseq/model_parallel/criterions/vocab_parallel_cross_entropy.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import math
7
+
8
+ from fairseq import metrics, utils
9
+ from fairseq.criterions import FairseqCriterion, register_criterion
10
+
11
+
12
+ try:
13
+ from fairseq.model_parallel.megatron.mpu.cross_entropy import (
14
+ vocab_parallel_cross_entropy,
15
+ )
16
+
17
+ has_megatron_submodule = True
18
+ except (ImportError, ModuleNotFoundError):
19
+ has_megatron_submodule = False
20
+
21
+
22
+ @register_criterion("vocab_parallel_cross_entropy")
23
+ class VocabParallelCrossEntropyCriterion(FairseqCriterion):
24
+ def __init__(self, task, sentence_avg):
25
+ super().__init__(task)
26
+ self.sentence_avg = sentence_avg
27
+ if not has_megatron_submodule:
28
+ raise ImportError(
29
+ "\n\nPlease install the megatron submodule:"
30
+ "\n\n git submodule update --init "
31
+ "fairseq/model_parallel/megatron"
32
+ )
33
+
34
+ def forward(self, model, sample, reduce=True):
35
+ """Compute the loss for the given sample.
36
+
37
+ Returns a tuple with three elements:
38
+ 1) the loss
39
+ 2) the sample size, which is used as the denominator for the gradient
40
+ 3) logging outputs to display while training
41
+ """
42
+ net_output = model(**sample["net_input"])
43
+ target = sample["target"]
44
+
45
+ loss = vocab_parallel_cross_entropy(net_output[0].float(), target)
46
+ loss = (loss * (target != self.padding_idx)).sum()
47
+ sample_size = (
48
+ sample["target"].size(0) if self.sentence_avg else sample["ntokens"]
49
+ )
50
+ logging_output = {
51
+ "loss": utils.item(loss.data) if reduce else loss.data,
52
+ "ntokens": sample["ntokens"],
53
+ "nsentences": sample["target"].size(0),
54
+ "sample_size": sample_size,
55
+ }
56
+ return loss, sample_size, logging_output
57
+
58
+ @staticmethod
59
+ def reduce_metrics(logging_outputs) -> None:
60
+ """Aggregate logging outputs from data parallel training."""
61
+ loss_sum = sum(log.get("loss", 0) for log in logging_outputs)
62
+ ntokens = sum(log.get("ntokens", 0) for log in logging_outputs)
63
+ sample_size = sum(log.get("sample_size", 0) for log in logging_outputs)
64
+
65
+ metrics.log_scalar(
66
+ "loss", loss_sum / sample_size / math.log(2), sample_size, round=3
67
+ )
68
+ if sample_size != ntokens:
69
+ metrics.log_scalar(
70
+ "nll_loss", loss_sum / ntokens / math.log(2), ntokens, round=3
71
+ )
72
+ metrics.log_derived(
73
+ "ppl", lambda meters: utils.get_perplexity(meters["nll_loss"].avg)
74
+ )
75
+ else:
76
+ metrics.log_derived(
77
+ "ppl", lambda meters: utils.get_perplexity(meters["loss"].avg)
78
+ )
79
+
80
+ @staticmethod
81
+ def logging_outputs_can_be_summed() -> bool:
82
+ """
83
+ Whether the logging outputs returned by `forward` can be summed
84
+ across workers prior to calling `reduce_metrics`. Setting this
85
+ to True will improves distributed training speed.
86
+ """
87
+ return True
avh-align_core/fairseq/model_parallel/models/__init__.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import importlib
7
+ import os
8
+
9
+
10
+ # automatically import any Python files in the models/ directory
11
+ models_dir = os.path.dirname(__file__)
12
+ for file in os.listdir(models_dir):
13
+ path = os.path.join(models_dir, file)
14
+ if (
15
+ not file.startswith("_")
16
+ and not file.startswith(".")
17
+ and (file.endswith(".py") or os.path.isdir(path))
18
+ ):
19
+ model_name = file[: file.find(".py")] if file.endswith(".py") else file
20
+ module = importlib.import_module("fairseq.model_parallel.models." + model_name)
avh-align_core/fairseq/model_parallel/models/pipeline_parallel_transformer/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ from .model import * # noqa
avh-align_core/fairseq/model_parallel/models/pipeline_parallel_transformer/layers.py ADDED
@@ -0,0 +1,600 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import math
7
+ from collections import namedtuple
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+ from fairseq import options, utils
13
+ from fairseq.modules import (
14
+ AdaptiveSoftmax,
15
+ LayerNorm,
16
+ MultiheadAttention,
17
+ PositionalEmbedding,
18
+ )
19
+
20
+
21
+ EncoderOut = namedtuple(
22
+ "TransformerEncoderOut",
23
+ [
24
+ "encoder_out", # T x B x C
25
+ "encoder_padding_mask", # B x T
26
+ "encoder_embedding", # B x T x C
27
+ "encoder_states", # List[T x B x C]
28
+ ],
29
+ )
30
+
31
+
32
+ class TransformerEncoderEmbedding(nn.Module):
33
+ """ Encoder Embedding + Positional Embedding """
34
+
35
+ def __init__(self, args, embed_tokens):
36
+ super().__init__()
37
+ self.dropout = args.dropout
38
+ self.max_source_positions = args.max_source_positions
39
+ self.embed_tokens = embed_tokens
40
+ if isinstance(embed_tokens, nn.ModuleList):
41
+ self.padding_idx = embed_tokens[0].padding_idx
42
+ embed_dim = sum(e.embedding_dim for e in embed_tokens)
43
+ else:
44
+ self.padding_idx = embed_tokens.padding_idx
45
+ embed_dim = embed_tokens.embedding_dim
46
+ self.embed_scale = math.sqrt(embed_dim)
47
+ self.embed_positions = (
48
+ PositionalEmbedding(
49
+ args.max_source_positions,
50
+ embed_dim,
51
+ self.padding_idx,
52
+ learned=args.encoder_learned_pos,
53
+ )
54
+ if not args.no_token_positional_embeddings
55
+ else None
56
+ )
57
+ if getattr(args, "layernorm_embedding", False):
58
+ self.layernorm_embedding = LayerNorm(embed_dim)
59
+ else:
60
+ self.layernorm_embedding = None
61
+
62
+ def forward(self, input):
63
+ # embed tokens and positions
64
+ src_tokens = input[0]
65
+ prev_output_tokens = input[2]
66
+ if isinstance(self.embed_tokens, nn.ModuleList):
67
+ x_embed_list = []
68
+ for embed_tokens_part in self.embed_tokens:
69
+ x_embed_list.append(embed_tokens_part(src_tokens))
70
+
71
+ embedded = torch.cat(x_embed_list, dim=-1)
72
+ else:
73
+ embedded = self.embed_tokens(src_tokens)
74
+ x = embed = self.embed_scale * embedded
75
+ if self.embed_positions is not None:
76
+ x = embed + self.embed_positions(src_tokens)
77
+ if self.layernorm_embedding:
78
+ x = self.layernorm_embedding(x)
79
+ x = F.dropout(x, p=self.dropout, training=self.training)
80
+ # B x T x C -> T x B x C
81
+ x = x.transpose(0, 1)
82
+
83
+ # compute padding mask
84
+ encoder_padding_mask = src_tokens.eq(self.padding_idx)
85
+ return (x, encoder_padding_mask, prev_output_tokens)
86
+
87
+
88
+ class TransformerEncoderLayerNorm(nn.Module):
89
+ """
90
+ Layer norm at the the end of all encoder layers if
91
+ args.encoder_enormalize_before = True
92
+ """
93
+
94
+ def __init__(self, args, embed_dim):
95
+ super().__init__()
96
+ if args.encoder_normalize_before:
97
+ self.layer_norm = LayerNorm(embed_dim)
98
+ else:
99
+ self.layer_norm = None
100
+
101
+ def forward(self, input):
102
+ x = input[0]
103
+ encoder_padding_mask = input[1]
104
+ prev_output_tokens = input[2]
105
+ if self.layer_norm:
106
+ x = self.layer_norm(x)
107
+ # keeping track of the incremental_state is not supported yet
108
+ return (x, encoder_padding_mask, prev_output_tokens)
109
+
110
+
111
+ class TransformerDecoderEmbedding(nn.Module):
112
+ """ Decoder Embedding + Positional Embedding """
113
+
114
+ def __init__(self, args, embed_tokens):
115
+ super().__init__()
116
+ self.dropout = args.dropout
117
+ self.share_input_output_embed = args.share_decoder_input_output_embed
118
+ input_embed_dim = (
119
+ sum(e.embedding_dim for e in embed_tokens)
120
+ if isinstance(embed_tokens, nn.ModuleList)
121
+ else embed_tokens.embedding_dim
122
+ )
123
+ embed_dim = args.decoder_embed_dim
124
+ self.output_embed_dim = args.decoder_output_dim
125
+
126
+ padding_idx = (
127
+ embed_tokens[0].padding_idx
128
+ if isinstance(embed_tokens, nn.ModuleList)
129
+ else embed_tokens.padding_idx
130
+ )
131
+ self.max_target_positions = args.max_target_positions
132
+
133
+ self.embed_tokens = embed_tokens
134
+ self.embed_scale = math.sqrt(embed_dim) # todo: try with input_embed_dim
135
+
136
+ self.project_in_dim = (
137
+ Linear(input_embed_dim, embed_dim, bias=False)
138
+ if embed_dim != input_embed_dim
139
+ else None
140
+ )
141
+
142
+ self.embed_positions = (
143
+ PositionalEmbedding(
144
+ args.max_target_positions,
145
+ embed_dim,
146
+ padding_idx,
147
+ learned=args.decoder_learned_pos,
148
+ )
149
+ if not args.no_token_positional_embeddings
150
+ else None
151
+ )
152
+
153
+ def forward(self, input):
154
+ mt_task = False
155
+ if isinstance(input, tuple):
156
+ if len(input) == 3:
157
+ encoder_out = input[0]
158
+ encoder_padding_mask = input[1]
159
+ prev_output_tokens = input[2]
160
+ incremental_state = None # Hardcoding to avoid passing of None objects
161
+ mt_task = True
162
+ else:
163
+ # HACK for now, need to fix (TODO sidgoyal)
164
+ prev_output_tokens = input[0]
165
+ # discard "src_lengths"
166
+ encoder_out = None
167
+ encoder_padding_mask = None
168
+ incremental_state = None
169
+
170
+ else:
171
+ prev_output_tokens = input
172
+ encoder_out = None
173
+ encoder_padding_mask = None
174
+ incremental_state = None
175
+
176
+ positions = (
177
+ self.embed_positions(
178
+ prev_output_tokens,
179
+ incremental_state=incremental_state,
180
+ )
181
+ if self.embed_positions is not None
182
+ else None
183
+ )
184
+
185
+ if incremental_state is not None:
186
+ prev_output_tokens = prev_output_tokens[:, -1:]
187
+ if positions is not None:
188
+ positions = positions[:, -1:]
189
+
190
+ # embed tokens and positions
191
+
192
+ if isinstance(self.embed_tokens, nn.ModuleList):
193
+ x_embed_list = []
194
+ for embed_tokens_part in self.embed_tokens:
195
+ x_embed_list.append(embed_tokens_part(prev_output_tokens))
196
+
197
+ x = self.embed_scale * torch.cat(x_embed_list, dim=-1)
198
+ else:
199
+ x = self.embed_scale * self.embed_tokens(prev_output_tokens)
200
+
201
+ if self.project_in_dim is not None:
202
+ x = self.project_in_dim(x)
203
+
204
+ if positions is not None:
205
+ x += positions
206
+ x = F.dropout(x, p=self.dropout, training=self.training)
207
+
208
+ # B x T x C -> T x B x C
209
+ x = x.transpose(0, 1)
210
+ if mt_task:
211
+ return (x, encoder_out, encoder_padding_mask)
212
+ return x
213
+
214
+
215
+ class TransformerDecoderOutputLayer(nn.Module):
216
+ def __init__(self, args, embed_tokens, dictionary):
217
+ super().__init__()
218
+ self.share_input_output_embed = args.share_decoder_input_output_embed
219
+ self.embed_tokens = embed_tokens
220
+ self.output_embed_dim = args.decoder_output_dim
221
+ embed_dim = args.decoder_embed_dim
222
+
223
+ self.project_out_dim = (
224
+ Linear(embed_dim, self.output_embed_dim, bias=False)
225
+ if embed_dim != self.output_embed_dim and not args.tie_adaptive_weights
226
+ else None
227
+ )
228
+ self.adaptive_softmax = None
229
+ if args.adaptive_softmax_cutoff is not None:
230
+ assert not isinstance(embed_tokens, nn.ModuleList)
231
+ self.adaptive_softmax = AdaptiveSoftmax(
232
+ len(dictionary),
233
+ self.output_embed_dim,
234
+ options.eval_str_list(args.adaptive_softmax_cutoff, type=int),
235
+ dropout=args.adaptive_softmax_dropout,
236
+ adaptive_inputs=embed_tokens if args.tie_adaptive_weights else None,
237
+ factor=args.adaptive_softmax_factor,
238
+ tie_proj=args.tie_adaptive_proj,
239
+ )
240
+ elif not self.share_input_output_embed:
241
+ self.embed_tokens = nn.Parameter(
242
+ torch.Tensor(len(dictionary), self.output_embed_dim)
243
+ )
244
+ nn.init.normal_(
245
+ self.embed_tokens, mean=0, std=self.output_embed_dim ** -0.5
246
+ )
247
+
248
+ if args.decoder_normalize_before and not getattr(
249
+ args, "no_decoder_final_norm", False
250
+ ):
251
+ self.layer_norm = LayerNorm(embed_dim)
252
+ else:
253
+ self.layer_norm = None
254
+
255
+ def forward(self, input, apply_final_proj=True):
256
+ if isinstance(input, tuple):
257
+ x = input[0]
258
+ else:
259
+ x = input
260
+
261
+ if self.layer_norm:
262
+ x = self.layer_norm(x)
263
+
264
+ # T x B x C -> B x T x C
265
+ x = x.transpose(0, 1)
266
+
267
+ if self.project_out_dim is not None:
268
+ x = self.project_out_dim(x)
269
+ if apply_final_proj:
270
+ x = self.output_layer(x)
271
+ return x
272
+
273
+ def output_layer(self, features, **kwargs):
274
+ """Project features to the vocabulary size."""
275
+ if self.adaptive_softmax is None:
276
+ # project back to size of vocabulary
277
+ if self.share_input_output_embed:
278
+ if isinstance(self.embed_tokens, nn.ModuleList):
279
+ output = None
280
+ for i, emb in enumerate(self.embed_tokens):
281
+ sidx = i * emb.embedding_dim
282
+ eidx = (i + 1) * emb.embedding_dim
283
+ if output is None:
284
+ output = F.linear(features[:, :, sidx:eidx], emb.weight)
285
+ else:
286
+ output += F.linear(features[:, :, sidx:eidx], emb.weight)
287
+
288
+ return output
289
+ else:
290
+ return F.linear(features, self.embed_tokens.weight)
291
+ else:
292
+ return F.linear(features, self.embed_tokens)
293
+ else:
294
+ return features
295
+
296
+
297
+ class TransformerEncoderLayer(nn.Module):
298
+ """Encoder layer block.
299
+ In the original paper each operation (multi-head attention or FFN) is
300
+ postprocessed with: `dropout -> add residual -> layernorm`. In the
301
+ tensor2tensor code they suggest that learning is more robust when
302
+ preprocessing each layer with layernorm and postprocessing with:
303
+ `dropout -> add residual`. We default to the approach in the paper, but the
304
+ tensor2tensor approach can be enabled by setting
305
+ *args.encoder_normalize_before* to ``True``.
306
+
307
+ Args:
308
+ args (argparse.Namespace): parsed command-line arguments
309
+ """
310
+
311
+ def __init__(self, args):
312
+ super().__init__()
313
+ self.embed_dim = args.encoder_embed_dim
314
+ self.self_attn = MultiheadAttention(
315
+ self.embed_dim,
316
+ args.encoder_attention_heads,
317
+ dropout=args.attention_dropout,
318
+ self_attention=True,
319
+ )
320
+ self.self_attn_layer_norm = LayerNorm(self.embed_dim)
321
+ self.dropout = args.dropout
322
+ self.activation_fn = utils.get_activation_fn(
323
+ activation=getattr(args, "activation_fn", "relu")
324
+ )
325
+ self.activation_dropout = getattr(args, "activation_dropout", 0)
326
+ if self.activation_dropout == 0:
327
+ # for backwards compatibility with models that use args.relu_dropout
328
+ self.activation_dropout = getattr(args, "relu_dropout", 0)
329
+ self.normalize_before = args.encoder_normalize_before
330
+ self.fc1 = Linear(self.embed_dim, args.encoder_ffn_embed_dim)
331
+ self.fc2 = Linear(args.encoder_ffn_embed_dim, self.embed_dim)
332
+ self.final_layer_norm = LayerNorm(self.embed_dim)
333
+
334
+ def upgrade_state_dict_named(self, state_dict, name):
335
+ """
336
+ Rename layer norm states from `...layer_norms.0.weight` to
337
+ `...self_attn_layer_norm.weight` and `...layer_norms.1.weight` to
338
+ `...final_layer_norm.weight`
339
+ """
340
+ layer_norm_map = {"0": "self_attn_layer_norm", "1": "final_layer_norm"}
341
+ for old, new in layer_norm_map.items():
342
+ for m in ("weight", "bias"):
343
+ k = "{}.layer_norms.{}.{}".format(name, old, m)
344
+ if k in state_dict:
345
+ state_dict["{}.{}.{}".format(name, new, m)] = state_dict[k]
346
+ del state_dict[k]
347
+
348
+ def forward(self, input):
349
+ """
350
+ Args:
351
+ input (Tuple):
352
+ input[0] (Tensor): input to the layer of shape `(seq_len, batch, embed_dim)`
353
+ input[1] (ByteTensor/FloatTensor): encoder padding mask -
354
+ binary ByteTensor of shape `(batch, src_len)` where padding elements
355
+ are indicated by ``1``.
356
+ input[2] (LongTensor): previous decoder outputs of shape
357
+ `(batch, tgt_len)`, for teacher forcing)
358
+ Returns:
359
+ output (Tuple):
360
+ output[0] (Tensor): encoded output of shape `(batch, src_len, embed_dim)`
361
+ output[1] (ByteTensor/FloatTensor): encoder padding mask
362
+ output[2] (LongTensor): previous decoder outputs
363
+ """
364
+ x = input[0]
365
+ encoder_padding_mask = input[1]
366
+ prev_output_tokens = input[2]
367
+ residual = x
368
+ x = self.maybe_layer_norm(self.self_attn_layer_norm, x, before=True)
369
+ x, _ = self.self_attn(
370
+ query=x, key=x, value=x, key_padding_mask=encoder_padding_mask
371
+ )
372
+ x = F.dropout(x, p=self.dropout, training=self.training)
373
+ x = residual + x
374
+ x = self.maybe_layer_norm(self.self_attn_layer_norm, x, after=True)
375
+
376
+ residual = x
377
+ x = self.maybe_layer_norm(self.final_layer_norm, x, before=True)
378
+ x = self.activation_fn(self.fc1(x))
379
+ x = F.dropout(x, p=self.activation_dropout, training=self.training)
380
+ x = self.fc2(x)
381
+ x = F.dropout(x, p=self.dropout, training=self.training)
382
+ x = residual + x
383
+ x = self.maybe_layer_norm(self.final_layer_norm, x, after=True)
384
+ return (x, encoder_padding_mask, prev_output_tokens)
385
+
386
+ def maybe_layer_norm(self, layer_norm, x, before=False, after=False):
387
+ assert before ^ after
388
+ if after ^ self.normalize_before:
389
+ return layer_norm(x)
390
+ else:
391
+ return x
392
+
393
+
394
+ class TransformerDecoderLayer(nn.Module):
395
+ """Decoder layer block.
396
+
397
+ In the original paper each operation (multi-head attention, encoder
398
+ attention or FFN) is postprocessed with: `dropout -> add residual ->
399
+ layernorm`. In the tensor2tensor code they suggest that learning is more
400
+ robust when preprocessing each layer with layernorm and postprocessing with:
401
+ `dropout -> add residual`. We default to the approach in the paper, but the
402
+ tensor2tensor approach can be enabled by setting
403
+ *args.decoder_normalize_before* to ``True``.
404
+
405
+ Args:
406
+ args (argparse.Namespace): parsed command-line arguments
407
+ no_encoder_attn (bool, optional): whether to attend to encoder outputs
408
+ (default: False).
409
+ """
410
+
411
+ def __init__(
412
+ self, args, no_encoder_attn=False, add_bias_kv=False, add_zero_attn=False
413
+ ):
414
+ super().__init__()
415
+ self.embed_dim = args.decoder_embed_dim
416
+ self.self_attn = MultiheadAttention(
417
+ embed_dim=self.embed_dim,
418
+ num_heads=args.decoder_attention_heads,
419
+ dropout=args.attention_dropout,
420
+ add_bias_kv=add_bias_kv,
421
+ add_zero_attn=add_zero_attn,
422
+ self_attention=True,
423
+ )
424
+ self.dropout = args.dropout
425
+ self.activation_fn = utils.get_activation_fn(
426
+ activation=getattr(args, "activation_fn", "relu")
427
+ )
428
+ self.activation_dropout = getattr(args, "activation_dropout", 0)
429
+ if self.activation_dropout == 0:
430
+ # for backwards compatibility with models that use args.relu_dropout
431
+ self.activation_dropout = getattr(args, "relu_dropout", 0)
432
+ self.normalize_before = args.decoder_normalize_before
433
+
434
+ # use layerNorm rather than FusedLayerNorm for exporting.
435
+ # char_inputs can be used to determint this.
436
+ # TODO remove this once we update apex with the fix
437
+ export = getattr(args, "char_inputs", False)
438
+ self.self_attn_layer_norm = LayerNorm(self.embed_dim, export=export)
439
+
440
+ if no_encoder_attn:
441
+ self.encoder_attn = None
442
+ self.encoder_attn_layer_norm = None
443
+ else:
444
+ self.encoder_attn = MultiheadAttention(
445
+ self.embed_dim,
446
+ args.decoder_attention_heads,
447
+ kdim=getattr(args, "encoder_embed_dim", None),
448
+ vdim=getattr(args, "encoder_embed_dim", None),
449
+ dropout=args.attention_dropout,
450
+ encoder_decoder_attention=True,
451
+ )
452
+ self.encoder_attn_layer_norm = LayerNorm(self.embed_dim, export=export)
453
+
454
+ self.fc1 = Linear(self.embed_dim, args.decoder_ffn_embed_dim)
455
+ self.fc2 = Linear(args.decoder_ffn_embed_dim, self.embed_dim)
456
+
457
+ self.final_layer_norm = LayerNorm(self.embed_dim, export=export)
458
+ self.need_attn = True
459
+
460
+ self.onnx_trace = False
461
+
462
+ def prepare_for_onnx_export_(self):
463
+ self.onnx_trace = True
464
+
465
+ def forward(self, input):
466
+ """
467
+ Args:
468
+ input (Tuple):
469
+ input[0] (Tensor): input to the layer of shape `(seq_len, batch, embed_dim)`
470
+ input[1] (Tensor): encoder output of shape `(batch, src_len, embed_dim)`
471
+ input[2] (ByteTensor/FloatTensor): encoder padding mask -
472
+ binary ByteTensor of shape `(batch, src_len)` where padding elements
473
+ are indicated by ``1``.
474
+ Returns:
475
+ output (Tuple):
476
+ output[0] (Tensor): encoded output of shape `(batch, src_len, embed_dim)`
477
+ output[1] (ByteTensor/FloatTensor): encoder padding mask
478
+ output[2] (LongTensor): previous decoder outputs
479
+ """
480
+ # Note: incremental state is not yet supported
481
+ mt_task = False
482
+ if isinstance(input, tuple):
483
+ x = input[0]
484
+ encoder_out = input[1]
485
+ encoder_padding_mask = input[2]
486
+ incremental_state = None
487
+ mt_task = True
488
+ else:
489
+ x = input
490
+ encoder_out = None
491
+ encoder_padding_mask = None
492
+ incremental_state = None
493
+
494
+ if incremental_state is None:
495
+ self_attn_mask = self.buffered_future_mask(x)
496
+ else:
497
+ self_attn_mask = None
498
+
499
+ # TODO: add back prev_self_attn_state, prev_attn_state,
500
+ # self_attn_padding_mask
501
+ prev_self_attn_state = None
502
+ prev_attn_state = None
503
+ self_attn_padding_mask = None
504
+
505
+ residual = x
506
+ x = self.maybe_layer_norm(self.self_attn_layer_norm, x, before=True)
507
+ if prev_self_attn_state is not None:
508
+ if incremental_state is None:
509
+ incremental_state = {}
510
+ prev_key, prev_value = prev_self_attn_state
511
+ saved_state = {"prev_key": prev_key, "prev_value": prev_value}
512
+ self.self_attn._set_input_buffer(incremental_state, saved_state)
513
+ x, attn = self.self_attn(
514
+ query=x,
515
+ key=x,
516
+ value=x,
517
+ key_padding_mask=self_attn_padding_mask,
518
+ incremental_state=incremental_state,
519
+ need_weights=False,
520
+ attn_mask=self_attn_mask,
521
+ )
522
+ x = F.dropout(x, p=self.dropout, training=self.training)
523
+ x = residual + x
524
+ x = self.maybe_layer_norm(self.self_attn_layer_norm, x, after=True)
525
+
526
+ if self.encoder_attn is not None:
527
+ residual = x
528
+ x = self.maybe_layer_norm(self.encoder_attn_layer_norm, x, before=True)
529
+ if prev_attn_state is not None:
530
+ if incremental_state is None:
531
+ incremental_state = {}
532
+ prev_key, prev_value = prev_attn_state
533
+ saved_state = {"prev_key": prev_key, "prev_value": prev_value}
534
+ self.encoder_attn._set_input_buffer(incremental_state, saved_state)
535
+ x, attn = self.encoder_attn(
536
+ query=x,
537
+ key=encoder_out,
538
+ value=encoder_out,
539
+ key_padding_mask=encoder_padding_mask,
540
+ incremental_state=incremental_state,
541
+ static_kv=True,
542
+ need_weights=(not self.training and self.need_attn),
543
+ )
544
+ x = F.dropout(x, p=self.dropout, training=self.training)
545
+ x = residual + x
546
+ x = self.maybe_layer_norm(self.encoder_attn_layer_norm, x, after=True)
547
+
548
+ residual = x
549
+ x = self.maybe_layer_norm(self.final_layer_norm, x, before=True)
550
+ x = self.activation_fn(self.fc1(x))
551
+ x = F.dropout(x, p=self.activation_dropout, training=self.training)
552
+ x = self.fc2(x)
553
+ x = F.dropout(x, p=self.dropout, training=self.training)
554
+ x = residual + x
555
+ x = self.maybe_layer_norm(self.final_layer_norm, x, after=True)
556
+
557
+ if mt_task:
558
+ return (x, encoder_out, encoder_padding_mask)
559
+ return x
560
+
561
+ def buffered_future_mask(self, tensor):
562
+ dim = tensor.size(0)
563
+ if (
564
+ not hasattr(self, "_future_mask")
565
+ or self._future_mask is None
566
+ or self._future_mask.device != tensor.device
567
+ ):
568
+ self._future_mask = torch.triu(
569
+ utils.fill_with_neg_inf(tensor.new(dim, dim)), 1
570
+ )
571
+ if self._future_mask.size(0) < dim:
572
+ self._future_mask = torch.triu(
573
+ utils.fill_with_neg_inf(self._future_mask.resize_(dim, dim)), 1
574
+ )
575
+ return self._future_mask[:dim, :dim]
576
+
577
+ def maybe_layer_norm(self, layer_norm, x, before=False, after=False):
578
+ assert before ^ after
579
+ if after ^ self.normalize_before:
580
+ return layer_norm(x)
581
+ else:
582
+ return x
583
+
584
+ def make_generation_fast_(self, need_attn=False, **kwargs):
585
+ self.need_attn = need_attn
586
+
587
+
588
+ def Embedding(num_embeddings, embedding_dim, padding_idx):
589
+ m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx)
590
+ nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5)
591
+ nn.init.constant_(m.weight[padding_idx], 0)
592
+ return m
593
+
594
+
595
+ def Linear(in_features, out_features, bias=True):
596
+ m = nn.Linear(in_features, out_features, bias)
597
+ nn.init.xavier_uniform_(m.weight)
598
+ if bias:
599
+ nn.init.constant_(m.bias, 0.0)
600
+ return m
avh-align_core/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py ADDED
@@ -0,0 +1,767 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import logging
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ import torch.nn.functional as F
11
+ from fairseq import utils
12
+ from fairseq.model_parallel.models.pipeline_parallel_transformer.layers import (
13
+ Embedding,
14
+ TransformerDecoderEmbedding,
15
+ TransformerDecoderLayer,
16
+ TransformerDecoderOutputLayer,
17
+ TransformerEncoderEmbedding,
18
+ TransformerEncoderLayer,
19
+ TransformerEncoderLayerNorm,
20
+ )
21
+ from fairseq.models import (
22
+ BaseFairseqModel,
23
+ FairseqDecoder,
24
+ FairseqEncoder,
25
+ register_model,
26
+ register_model_architecture,
27
+ )
28
+ from fairseq.models.fairseq_encoder import EncoderOut
29
+ from fairseq.models.transformer import (
30
+ base_architecture,
31
+ transformer_iwslt_de_en,
32
+ transformer_wmt_en_de_big,
33
+ )
34
+ from fairseq.modules import SinusoidalPositionalEmbedding
35
+
36
+
37
+ logger = logging.getLogger(__name__)
38
+
39
+
40
+ DEFAULT_MAX_SOURCE_POSITIONS = 1024
41
+ DEFAULT_MAX_TARGET_POSITIONS = 1024
42
+ TORCH_PIPE = False
43
+ RPC_INIT = False
44
+
45
+ def import_pipe():
46
+ global TORCH_PIPE
47
+ global RPC_INIT
48
+ try:
49
+ from torch.distributed.pipeline.sync import Pipe # noqa
50
+ global Pipe
51
+ from torch.distributed.pipeline.sync.utils import partition_model
52
+ global partition_model
53
+ from torch.distributed import rpc
54
+ import tempfile
55
+ TORCH_PIPE = True
56
+ # Initialize single process RPC agent since TORCH_PIPE requires
57
+ # RRef. RRef depends on RPC being initialized and as a result we initialize
58
+ # RPC with a single node.
59
+ tmpfile = tempfile.NamedTemporaryFile()
60
+ if not RPC_INIT:
61
+ rpc.init_rpc(
62
+ name="worker",
63
+ rank=0,
64
+ world_size=1,
65
+ rpc_backend_options=rpc.TensorPipeRpcBackendOptions(
66
+ init_method="file://{}".format(tmpfile.name),
67
+ )
68
+ )
69
+ RPC_INIT = True
70
+ logger.info('Using torch pipe')
71
+ except ImportError:
72
+ try:
73
+ from fairscale.nn import Pipe # noqa
74
+ logger.info('Using fairscale pipe')
75
+ except ImportError:
76
+ raise ImportError("Please install fairscale with: pip install fairscale")
77
+
78
+
79
+ @register_model("pipeline_parallel_transformer")
80
+ class PipelineParallelTransformerModel(BaseFairseqModel):
81
+ def __init__(self, encoder, decoder, balance, devices, chunks, checkpoint):
82
+ import_pipe()
83
+ super().__init__()
84
+ assert isinstance(encoder, FairseqEncoder)
85
+ assert isinstance(decoder, FairseqDecoder)
86
+ encoder_module_list = (
87
+ [encoder.embedding_layer]
88
+ + list(encoder.encoder_layers)
89
+ + [encoder.final_layer_norm]
90
+ )
91
+ self.num_encoder_modules = len(encoder_module_list)
92
+ decoder_module_list = (
93
+ [decoder.embedding_layer]
94
+ + list(decoder.decoder_layers)
95
+ + [decoder.decoder_output_layer]
96
+ )
97
+ self.num_decoder_modules = len(decoder_module_list)
98
+ module_list = encoder_module_list + decoder_module_list
99
+ self.devices = devices
100
+ if TORCH_PIPE:
101
+ self.model = Pipe(
102
+ partition_model(nn.Sequential(*module_list), balance, devices),
103
+ chunks=chunks,
104
+ checkpoint=checkpoint,
105
+ )
106
+ else:
107
+ self.model = Pipe(
108
+ nn.Sequential(*module_list),
109
+ balance=balance,
110
+ devices=devices,
111
+ chunks=chunks,
112
+ checkpoint=checkpoint,
113
+ )
114
+ self.encoder_max_positions = self.max_positions_helper(
115
+ encoder.embedding_layer, "max_source_positions"
116
+ )
117
+ self.decoder_max_positions = self.max_positions_helper(
118
+ decoder.embedding_layer, "max_target_positions"
119
+ )
120
+ self.adaptive_softmax = getattr(decoder, "adaptive_softmax", None)
121
+ # Note: To be populated during inference
122
+ self.encoder = None
123
+ self.decoder = None
124
+
125
+ def forward(self, src_tokens, src_lengths, prev_output_tokens):
126
+ if self.training:
127
+ input_lst = [src_tokens, src_lengths, prev_output_tokens]
128
+ input = tuple(i.to(self.devices[0], non_blocking=True) for i in input_lst)
129
+ if TORCH_PIPE:
130
+ return self.model(input).local_value()
131
+ else:
132
+ return self.model(input)
133
+ else:
134
+ assert self.encoder is not None and self.decoder is not None, (
135
+ "encoder and decoder need to be initialized by "
136
+ + "calling the `prepare_for_inference_()` method"
137
+ )
138
+ encoder_output_tuple = self.encoder(input)
139
+ return self.decoder(encoder_output_tuple)
140
+
141
+ def prepare_for_inference_(self, cfg):
142
+ if self.encoder is not None and self.decoder is not None:
143
+ logger.info("Encoder and Decoder already initialized")
144
+ return
145
+ encoder_module_list = []
146
+ decoder_module_list = []
147
+ module_count = 0
148
+ for partition in self.model.partitions:
149
+ for module in partition:
150
+ if module_count < self.num_encoder_modules:
151
+ encoder_module_list.append(module)
152
+ else:
153
+ decoder_module_list.append(module)
154
+ module_count += 1
155
+ self.model = None
156
+ self.encoder = TransformerEncoder(cfg.distributed_training, None, None, encoder_module_list)
157
+ self.decoder = TransformerDecoder(
158
+ cfg.distributed_training, None, None, decoder_module_list=decoder_module_list
159
+ )
160
+
161
+ @staticmethod
162
+ def add_args(parser):
163
+ """Add model-specific arguments to the parser."""
164
+ # fmt: off
165
+ parser.add_argument('--activation-fn',
166
+ choices=utils.get_available_activation_fns(),
167
+ help='activation function to use')
168
+ parser.add_argument('--dropout', type=float, metavar='D',
169
+ help='dropout probability')
170
+ parser.add_argument('--attention-dropout', type=float, metavar='D',
171
+ help='dropout probability for attention weights')
172
+ parser.add_argument('--activation-dropout', '--relu-dropout', type=float, metavar='D',
173
+ help='dropout probability after activation in FFN.')
174
+ parser.add_argument('--encoder-embed-path', type=str, metavar='STR',
175
+ help='path to pre-trained encoder embedding')
176
+ parser.add_argument('--encoder-embed-dim', type=int, metavar='N',
177
+ help='encoder embedding dimension')
178
+ parser.add_argument('--encoder-ffn-embed-dim', type=int, metavar='N',
179
+ help='encoder embedding dimension for FFN')
180
+ parser.add_argument('--encoder-layers', type=int, metavar='N',
181
+ help='num encoder layers')
182
+ parser.add_argument('--encoder-attention-heads', type=int, metavar='N',
183
+ help='num encoder attention heads')
184
+ parser.add_argument('--encoder-normalize-before', action='store_true',
185
+ help='apply layernorm before each encoder block')
186
+ parser.add_argument('--encoder-learned-pos', action='store_true',
187
+ help='use learned positional embeddings in the encoder')
188
+ parser.add_argument('--decoder-embed-path', type=str, metavar='STR',
189
+ help='path to pre-trained decoder embedding')
190
+ parser.add_argument('--decoder-embed-dim', type=int, metavar='N',
191
+ help='decoder embedding dimension')
192
+ parser.add_argument('--decoder-ffn-embed-dim', type=int, metavar='N',
193
+ help='decoder embedding dimension for FFN')
194
+ parser.add_argument('--decoder-layers', type=int, metavar='N',
195
+ help='num decoder layers')
196
+ parser.add_argument('--decoder-attention-heads', type=int, metavar='N',
197
+ help='num decoder attention heads')
198
+ parser.add_argument('--decoder-learned-pos', action='store_true',
199
+ help='use learned positional embeddings in the decoder')
200
+ parser.add_argument('--decoder-normalize-before', action='store_true',
201
+ help='apply layernorm before each decoder block')
202
+ parser.add_argument('--share-decoder-input-output-embed', action='store_true',
203
+ help='share decoder input and output embeddings')
204
+ parser.add_argument('--share-all-embeddings', action='store_true',
205
+ help='share encoder, decoder and output embeddings'
206
+ ' (requires shared dictionary and embed dim)')
207
+ parser.add_argument('--no-token-positional-embeddings', default=False, action='store_true',
208
+ help='if set, disables positional embeddings (outside self attention)')
209
+ parser.add_argument('--adaptive-softmax-cutoff', metavar='EXPR',
210
+ help='comma separated list of adaptive softmax cutoff points. '
211
+ 'Must be used with adaptive_loss criterion'),
212
+ parser.add_argument('--adaptive-softmax-dropout', type=float, metavar='D',
213
+ help='sets adaptive softmax dropout for the tail projections')
214
+ parser.add_argument('--num-embedding-chunks', type=int, metavar='N', default=1,
215
+ help='Number of embedding layer chunks (enables more even distribution'
216
+ 'of optimizer states across data parallel nodes'
217
+ 'when using optimizer state sharding and'
218
+ 'a big embedding vocabulary)')
219
+ # fmt: on
220
+
221
+ @classmethod
222
+ def build_model_base(cls, args, task):
223
+ """Build a new model instance."""
224
+
225
+ # make sure all arguments are present in older models
226
+ base_architecture(args)
227
+
228
+ if not hasattr(args, "max_source_positions"):
229
+ args.max_source_positions = DEFAULT_MAX_SOURCE_POSITIONS
230
+ if not hasattr(args, "max_target_positions"):
231
+ args.max_target_positions = DEFAULT_MAX_TARGET_POSITIONS
232
+
233
+ src_dict, tgt_dict = task.source_dictionary, task.target_dictionary
234
+
235
+ def build_embedding(dictionary, embed_dim, path=None, num_embed_chunks=1):
236
+ assert embed_dim % num_embed_chunks == 0, (
237
+ f"Number of embedding chunks = {num_embed_chunks} should be "
238
+ + f"divisible by the embedding dimension = {embed_dim}"
239
+ )
240
+ assert path is None or num_embed_chunks == 1, (
241
+ "Loading embedding from a path with number of embedding chunks > 1"
242
+ + " is not yet supported"
243
+ )
244
+ num_embeddings = len(dictionary)
245
+ padding_idx = dictionary.pad()
246
+ # if provided, load from preloaded dictionaries
247
+ if path:
248
+ emb = Embedding(num_embeddings, embed_dim, padding_idx)
249
+ embed_dict = utils.parse_embedding(path)
250
+ utils.load_embedding(embed_dict, dictionary, emb)
251
+ else:
252
+ embed_chunk_dim = embed_dim // num_embed_chunks
253
+ emb = nn.ModuleList()
254
+ for i in range(num_embed_chunks):
255
+ emb.append(Embedding(num_embeddings, embed_chunk_dim, padding_idx))
256
+ return emb
257
+
258
+ num_embed_chunks = args.num_embedding_chunks
259
+ if args.share_all_embeddings:
260
+ if src_dict != tgt_dict:
261
+ raise ValueError("--share-all-embeddings requires a joined dictionary")
262
+ if args.encoder_embed_dim != args.decoder_embed_dim:
263
+ raise ValueError(
264
+ "--share-all-embeddings requires --encoder-embed-dim to match --decoder-embed-dim"
265
+ )
266
+ if args.decoder_embed_path and (
267
+ args.decoder_embed_path != args.encoder_embed_path
268
+ ):
269
+ raise ValueError(
270
+ "--share-all-embeddings not compatible with --decoder-embed-path"
271
+ )
272
+ encoder_embed_tokens = build_embedding(
273
+ src_dict,
274
+ args.encoder_embed_dim,
275
+ args.encoder_embed_path,
276
+ num_embed_chunks,
277
+ )
278
+ decoder_embed_tokens = encoder_embed_tokens
279
+ args.share_decoder_input_output_embed = True
280
+ else:
281
+ assert args.share_decoder_input_output_embed or num_embed_chunks == 1, (
282
+ "Not sharing decoder I/O embeddings is not yet supported with number of "
283
+ + "embedding chunks > 1"
284
+ )
285
+ encoder_embed_tokens = build_embedding(
286
+ src_dict,
287
+ args.encoder_embed_dim,
288
+ args.encoder_embed_path,
289
+ num_embed_chunks,
290
+ )
291
+ decoder_embed_tokens = build_embedding(
292
+ tgt_dict,
293
+ args.decoder_embed_dim,
294
+ args.decoder_embed_path,
295
+ num_embed_chunks,
296
+ )
297
+
298
+ encoder = cls.build_encoder(args, src_dict, encoder_embed_tokens)
299
+ decoder = cls.build_decoder(args, tgt_dict, decoder_embed_tokens)
300
+ return (encoder, decoder)
301
+
302
+ @classmethod
303
+ def build_encoder(cls, args, src_dict, embed_tokens):
304
+ return TransformerEncoder(args, src_dict, embed_tokens)
305
+
306
+ @classmethod
307
+ def build_decoder(cls, args, tgt_dict, embed_tokens):
308
+ return TransformerDecoder(args, tgt_dict, embed_tokens)
309
+
310
+ @classmethod
311
+ def build_model(cls, args, task):
312
+ encoder, decoder = cls.build_model_base(args, task)
313
+ return PipelineParallelTransformerModel(
314
+ encoder=encoder,
315
+ decoder=decoder,
316
+ balance=utils.eval_str_list(args.pipeline_balance, type=int),
317
+ devices=utils.eval_str_list(args.pipeline_devices, type=int),
318
+ chunks=args.pipeline_chunks,
319
+ checkpoint=args.pipeline_checkpoint,
320
+ )
321
+
322
+ def output_layer(self, features, **kwargs):
323
+ """Project features to the default output size (typically vocabulary size)."""
324
+ return self.decoder.output_layer(features, **kwargs)
325
+
326
+ def max_positions(self):
327
+ """Maximum length supported by the model."""
328
+ return (self.encoder_max_positions, self.decoder_max_positions)
329
+
330
+ def max_positions_helper(
331
+ self, embedding_layer, max_positions_field="max_source_positions"
332
+ ):
333
+ """Maximum input length supported by the encoder or decoder."""
334
+ if embedding_layer.embed_positions is None:
335
+ return getattr(embedding_layer, max_positions_field)
336
+ return min(
337
+ getattr(embedding_layer, max_positions_field),
338
+ embedding_layer.embed_positions.max_positions,
339
+ )
340
+
341
+ def get_normalized_probs(self, net_output, log_probs, sample=None):
342
+ """Get normalized probabilities (or log probs) from a net's output."""
343
+
344
+ if hasattr(self, "adaptive_softmax") and self.adaptive_softmax is not None:
345
+ if sample is not None:
346
+ assert "target" in sample
347
+ target = sample["target"]
348
+ else:
349
+ target = None
350
+ out = self.adaptive_softmax.get_log_prob(net_output, target=target)
351
+ return out.exp_() if not log_probs else out
352
+
353
+ # A Pipe() module returns a tuple of tensors as the output.
354
+ # In this case, the tuple has one element - the output tensor of logits
355
+ logits = net_output if isinstance(net_output, torch.Tensor) else net_output[0]
356
+ if log_probs:
357
+ return utils.log_softmax(logits, dim=-1, onnx_trace=False)
358
+ else:
359
+ return utils.softmax(logits, dim=-1, onnx_trace=False)
360
+
361
+ def max_decoder_positions(self):
362
+ """Maximum length supported by the decoder."""
363
+ return self.decoder_max_positions
364
+
365
+ def load_state_dict(self, state_dict, strict=True, model_cfg=None):
366
+ """Copies parameters and buffers from *state_dict* into this module and
367
+ its descendants.
368
+
369
+ Overrides the method in :class:`nn.Module`. Compared with that method
370
+ this additionally "upgrades" *state_dicts* from old checkpoints.
371
+ """
372
+ self.upgrade_state_dict(state_dict)
373
+ is_regular_transformer = not any("model.partitions" in k for k in state_dict)
374
+ if is_regular_transformer:
375
+ state_dict = self.convert_to_pipeline_parallel_state_dict(state_dict)
376
+ return super().load_state_dict(state_dict, strict)
377
+
378
+ def convert_to_pipeline_parallel_state_dict(self, state_dict):
379
+ new_state_dict = self.state_dict()
380
+ encoder_layer_idx = 0
381
+ decoder_layer_idx = 0
382
+ encoder_key_suffixes = [
383
+ "self_attn.k_proj.weight",
384
+ "self_attn.k_proj.bias",
385
+ "self_attn.v_proj.weight",
386
+ "self_attn.v_proj.bias",
387
+ "self_attn.q_proj.weight",
388
+ "self_attn.q_proj.bias",
389
+ "self_attn.out_proj.weight",
390
+ "self_attn.out_proj.bias",
391
+ "self_attn_layer_norm.weight",
392
+ "self_attn_layer_norm.bias",
393
+ "fc1.weight",
394
+ "fc1.bias",
395
+ "fc2.weight",
396
+ "fc2.bias",
397
+ "final_layer_norm.weight",
398
+ "final_layer_norm.bias",
399
+ ]
400
+ decoder_key_suffixes = [
401
+ "self_attn.k_proj.weight",
402
+ "self_attn.k_proj.bias",
403
+ "self_attn.v_proj.weight",
404
+ "self_attn.v_proj.bias",
405
+ "self_attn.q_proj.weight",
406
+ "self_attn.q_proj.bias",
407
+ "self_attn.out_proj.weight",
408
+ "self_attn.out_proj.bias",
409
+ "self_attn_layer_norm.weight",
410
+ "self_attn_layer_norm.bias",
411
+ "encoder_attn.k_proj.weight",
412
+ "encoder_attn.k_proj.bias",
413
+ "encoder_attn.v_proj.weight",
414
+ "encoder_attn.v_proj.bias",
415
+ "encoder_attn.q_proj.weight",
416
+ "encoder_attn.q_proj.bias",
417
+ "encoder_attn.out_proj.weight",
418
+ "encoder_attn.out_proj.bias",
419
+ "encoder_attn_layer_norm.weight",
420
+ "encoder_attn_layer_norm.bias",
421
+ "fc1.weight",
422
+ "fc1.bias",
423
+ "fc2.weight",
424
+ "fc2.bias",
425
+ "final_layer_norm.weight",
426
+ "final_layer_norm.bias",
427
+ ]
428
+ for pid, partition in enumerate(self.model.partitions):
429
+ logger.info(f"Begin Partition {pid}")
430
+ for mid, module in enumerate(partition):
431
+ # fmt: off
432
+ if isinstance(module, TransformerEncoderEmbedding):
433
+ new_state_dict[f'model.partitions.{pid}.{mid}.embed_tokens.weight'] = state_dict['encoder.embed_tokens.weight']
434
+ new_state_dict[f'model.partitions.{pid}.{mid}.embed_positions._float_tensor'] = state_dict['encoder.embed_positions._float_tensor']
435
+ if isinstance(module, TransformerEncoderLayer):
436
+ for suffix in encoder_key_suffixes:
437
+ new_state_dict[f'model.partitions.{pid}.{mid}.{suffix}'] = state_dict[f'encoder.layers.{encoder_layer_idx}.{suffix}']
438
+ encoder_layer_idx += 1
439
+ if isinstance(module, TransformerDecoderLayer):
440
+ for suffix in decoder_key_suffixes:
441
+ new_state_dict[f'model.partitions.{pid}.{mid}.{suffix}'] = state_dict[f'decoder.layers.{decoder_layer_idx}.{suffix}']
442
+ decoder_layer_idx += 1
443
+ if isinstance(module, TransformerEncoderLayerNorm):
444
+ if 'encoder.layer_norm.weight' in state_dict:
445
+ new_state_dict[f'model.partitions.{pid}.{mid}.layer_norm.weight'] = state_dict['encoder.layer_norm.weight']
446
+ new_state_dict[f'model.partitions.{pid}.{mid}.layer_norm.bias'] = state_dict['encoder.layer_norm.bias']
447
+ if isinstance(module, TransformerDecoderEmbedding):
448
+ new_state_dict[f'model.partitions.{pid}.{mid}.embed_tokens.weight'] = state_dict['decoder.embed_tokens.weight']
449
+ new_state_dict[f'model.partitions.{pid}.{mid}.embed_positions._float_tensor'] = state_dict['decoder.embed_positions._float_tensor']
450
+ if isinstance(module, TransformerDecoderOutputLayer):
451
+ new_state_dict[f'model.partitions.{pid}.{mid}.output_projection.weight'] = state_dict['decoder.output_projection.weight']
452
+ # fmt: on
453
+ return new_state_dict
454
+
455
+
456
+ class TransformerEncoder(FairseqEncoder):
457
+ """
458
+ Transformer encoder consisting of *args.encoder_layers* layers. Each layer
459
+ is a :class:`TransformerEncoderLayer`.
460
+
461
+ Args:
462
+ args (argparse.Namespace): parsed command-line arguments
463
+ dictionary (~fairseq.data.Dictionary): encoding dictionary
464
+ embed_tokens (torch.nn.Embedding): input embedding
465
+ """
466
+
467
+ def __init__(self, args, dictionary, embed_tokens, encoder_module_list=None):
468
+ super().__init__(dictionary)
469
+ self.register_buffer("version", torch.Tensor([3]))
470
+ import_pipe()
471
+ self.use_pipeline = encoder_module_list is not None
472
+ if not self.use_pipeline:
473
+ self.embedding_layer = TransformerEncoderEmbedding(args, embed_tokens)
474
+ self.encoder_layers = nn.Sequential(*[TransformerEncoderLayer(args) for i in range(args.encoder_layers)])
475
+ if isinstance(embed_tokens, nn.ModuleList):
476
+ emb_dim = sum(e.embedding_dim for e in embed_tokens)
477
+ else:
478
+ emb_dim = embed_tokens.embedding_dim
479
+ self.final_layer_norm = TransformerEncoderLayerNorm(args, emb_dim)
480
+ else:
481
+ encoder_balance = utils.eval_str_list(
482
+ args.pipeline_encoder_balance, type=int
483
+ )
484
+ encoder_devices = utils.eval_str_list(
485
+ args.pipeline_encoder_devices, type=int
486
+ )
487
+ assert sum(encoder_balance) == len(encoder_module_list), (
488
+ f"Sum of encoder_balance={encoder_balance} is not equal "
489
+ + f"to num_encoder_modules={len(encoder_module_list)}"
490
+ )
491
+ if TORCH_PIPE:
492
+ self.model = Pipe(
493
+ module=partition_model(nn.Sequential(*encoder_module_list), encoder_balance, encoder_devices),
494
+ chunks=args.pipeline_chunks,
495
+ checkpoint=args.pipeline_checkpoint,
496
+ )
497
+ else:
498
+ self.model = Pipe(
499
+ module=nn.Sequential(*encoder_module_list),
500
+ balance=encoder_balance,
501
+ devices=encoder_devices,
502
+ chunks=args.pipeline_chunks,
503
+ checkpoint=args.pipeline_checkpoint,
504
+ )
505
+
506
+ def forward(self, src_tokens, src_lengths):
507
+ """
508
+ Args:
509
+ input_tuple(
510
+ src_tokens (LongTensor): tokens in the source language of shape
511
+ `(batch, src_len)`
512
+ src_lengths (torch.LongTensor): lengths of each source sentence of
513
+ shape `(batch)`
514
+ )
515
+
516
+ Returns:
517
+ output_tuple(
518
+ - **encoder_out** (Tensor): the last encoder layer's output of
519
+ shape `(src_len, batch, embed_dim)`
520
+ - **encoder_padding_mask** (ByteTensor): the positions of
521
+ padding elements of shape `(batch, src_len)`
522
+ - prev_output_tokens
523
+ - **encoder_states** (List[Tensor]): all intermediate
524
+ hidden states of shape `(src_len, batch, embed_dim)`.
525
+ Only populated if *return_all_hiddens* is True.
526
+ )
527
+ """
528
+ dummy_prev_output_tokens = torch.zeros(
529
+ 1, dtype=src_tokens.dtype, device=src_tokens.device
530
+ )
531
+ input_tuple = (src_tokens, src_lengths, dummy_prev_output_tokens)
532
+ if self.use_pipeline:
533
+ input_tuple = tuple(i.to(self.model.devices[0]) for i in input_tuple)
534
+ if TORCH_PIPE:
535
+ encoder_out = self.model(input_tuple).local_value()
536
+ else:
537
+ encoder_out = self.model(input_tuple)
538
+ else:
539
+ encoder_embed_output_tuple = self.embedding_layer(input_tuple)
540
+ encoder_layers_output = self.encoder_layers(encoder_embed_output_tuple)
541
+ encoder_out = self.final_layer_norm(encoder_layers_output)
542
+ # first element is the encoder output
543
+ # second element is the encoder padding mask
544
+ # the remaining elements of EncoderOut are not computed by
545
+ # the PipelineParallelTransformer
546
+ return EncoderOut(encoder_out[0], encoder_out[1], None, None, None, None)
547
+
548
+ def reorder_encoder_out(self, encoder_out, new_order):
549
+ """
550
+ Reorder encoder output according to *new_order*.
551
+
552
+ Args:
553
+ encoder_out: output from the ``forward()`` method
554
+ new_order (LongTensor): desired order
555
+
556
+ Returns:
557
+ *encoder_out* rearranged according to *new_order*
558
+ """
559
+ if encoder_out.encoder_out is not None:
560
+ encoder_out = encoder_out._replace(
561
+ encoder_out=encoder_out.encoder_out.index_select(1, new_order)
562
+ )
563
+ if encoder_out.encoder_padding_mask is not None:
564
+ encoder_out = encoder_out._replace(
565
+ encoder_padding_mask=encoder_out.encoder_padding_mask.index_select(
566
+ 0, new_order
567
+ )
568
+ )
569
+ if encoder_out.encoder_embedding is not None:
570
+ encoder_out = encoder_out._replace(
571
+ encoder_embedding=encoder_out.encoder_embedding.index_select(
572
+ 0, new_order
573
+ )
574
+ )
575
+ if encoder_out.encoder_states is not None:
576
+ for idx, state in enumerate(encoder_out.encoder_states):
577
+ encoder_out.encoder_states[idx] = state.index_select(1, new_order)
578
+ return encoder_out
579
+
580
+ def max_positions(self):
581
+ """Maximum input length supported by the encoder."""
582
+ if self.embedding_layer.embed_positions is None:
583
+ return self.embedding_layer.max_source_positions
584
+ return min(
585
+ self.embedding_layer.max_source_positions,
586
+ self.embedding_layer.embed_positions.max_positions,
587
+ )
588
+
589
+
590
+ class TransformerDecoder(FairseqDecoder):
591
+ """
592
+ Transformer decoder consisting of *args.decoder_layers* layers. Each layer
593
+ is a :class:`TransformerDecoderLayer`.
594
+
595
+ Args:
596
+ args (argparse.Namespace): parsed command-line arguments
597
+ dictionary (~fairseq.data.Dictionary): decoding dictionary
598
+ embed_tokens (torch.nn.Embedding): output embedding
599
+ no_encoder_attn (bool, optional): whether to attend to encoder outputs
600
+ (default: False).
601
+ """
602
+
603
+ def __init__(
604
+ self,
605
+ args,
606
+ dictionary,
607
+ embed_tokens,
608
+ no_encoder_attn=False,
609
+ decoder_module_list=None,
610
+ ):
611
+ super().__init__(dictionary)
612
+ self.register_buffer("version", torch.Tensor([3]))
613
+ import_pipe()
614
+ self.use_pipeline = decoder_module_list is not None
615
+ if not self.use_pipeline:
616
+ self.embedding_layer = TransformerDecoderEmbedding(args, embed_tokens)
617
+ self.decoder_layers = nn.Sequential(*[
618
+ TransformerDecoderLayer(args, no_encoder_attn)
619
+ for _ in range(args.decoder_layers)
620
+ ])
621
+ self.decoder_output_layer = TransformerDecoderOutputLayer(
622
+ args, embed_tokens, dictionary
623
+ )
624
+ else:
625
+ decoder_balance = utils.eval_str_list(
626
+ args.pipeline_decoder_balance, type=int
627
+ )
628
+ decoder_devices = utils.eval_str_list(
629
+ args.pipeline_decoder_devices, type=int
630
+ )
631
+ assert sum(decoder_balance) == len(decoder_module_list), (
632
+ f"Sum of decoder_balance={decoder_balance} is not equal "
633
+ + f"to num_decoder_modules={len(decoder_module_list)}"
634
+ )
635
+ if TORCH_PIPE:
636
+ self.model = Pipe(
637
+ module=partition_model(nn.Sequential(*decoder_module_list), decoder_balance, decoder_devices),
638
+ chunks=args.pipeline_chunks,
639
+ checkpoint=args.pipeline_checkpoint,
640
+ )
641
+ else:
642
+ self.model = Pipe(
643
+ module=nn.Sequential(*decoder_module_list),
644
+ balance=decoder_balance,
645
+ devices=decoder_devices,
646
+ chunks=args.pipeline_chunks,
647
+ checkpoint=args.pipeline_checkpoint,
648
+ )
649
+
650
+ def forward(
651
+ self,
652
+ prev_output_tokens,
653
+ encoder_out=None,
654
+ ):
655
+ """
656
+ Args:
657
+ prev_output_tokens (LongTensor): previous decoder outputs of shape
658
+ `(batch, tgt_len)`, for teacher forcing
659
+ encoder_out (optional): output from the encoder, used for
660
+ encoder-side attention
661
+ incremental_state (dict): dictionary used for storing state during
662
+ :ref:`Incremental decoding`
663
+ features_only (bool, optional): only return features without
664
+ applying output layer (default: False).
665
+
666
+ Returns:
667
+ tuple:
668
+ - the decoder's output of shape `(batch, tgt_len, vocab)`
669
+ - a dictionary with any model-specific outputs
670
+ """
671
+ input_tuple = (
672
+ encoder_out.encoder_out,
673
+ encoder_out.encoder_padding_mask,
674
+ prev_output_tokens,
675
+ )
676
+ if self.use_pipeline:
677
+ input_tuple = tuple(i.to(self.model.devices[0]) for i in input_tuple)
678
+ if TORCH_PIPE:
679
+ return (self.model(input_tuple).local_value(),)
680
+ else:
681
+ return (self.model(input_tuple),)
682
+ else:
683
+ embed_layer_output = self.embedding_layer(input_tuple)
684
+ state = self.decoder_layers(embed_layer_output)
685
+ return (self.decoder_output_layer(state),)
686
+
687
+ def output_layer(self, features, **kwargs):
688
+ """Project features to the vocabulary size."""
689
+ if self.adaptive_softmax is None:
690
+ # project back to size of vocabulary
691
+ if self.share_input_output_embed:
692
+ return F.linear(features, self.embed_tokens.weight)
693
+ else:
694
+ return F.linear(features, self.embed_out)
695
+ else:
696
+ return features
697
+
698
+ def max_positions(self):
699
+ """Maximum output length supported by the decoder."""
700
+ if self.embedding_layer.embed_positions is None:
701
+ return self.embedding_layer.max_target_positions
702
+ return min(
703
+ self.embedding_layer.max_target_positions,
704
+ self.embedding_layer.embed_positions.max_positions,
705
+ )
706
+
707
+ def buffered_future_mask(self, tensor):
708
+ dim = tensor.size(0)
709
+ if (
710
+ not hasattr(self, "_future_mask")
711
+ or self._future_mask is None
712
+ or self._future_mask.device != tensor.device
713
+ or self._future_mask.size(0) < dim
714
+ ):
715
+ self._future_mask = torch.triu(
716
+ utils.fill_with_neg_inf(tensor.new(dim, dim)), 1
717
+ )
718
+ return self._future_mask[:dim, :dim]
719
+
720
+ def upgrade_state_dict_named(self, state_dict, name):
721
+ """Upgrade a (possibly old) state dict for new versions of fairseq."""
722
+ if isinstance(self.embed_positions, SinusoidalPositionalEmbedding):
723
+ weights_key = "{}.embed_positions.weights".format(name)
724
+ if weights_key in state_dict:
725
+ del state_dict[weights_key]
726
+ state_dict[
727
+ "{}.embed_positions._float_tensor".format(name)
728
+ ] = torch.FloatTensor(1)
729
+
730
+ for i in range(len(self.layers)):
731
+ # update layer norms
732
+ layer_norm_map = {
733
+ "0": "self_attn_layer_norm",
734
+ "1": "encoder_attn_layer_norm",
735
+ "2": "final_layer_norm",
736
+ }
737
+ for old, new in layer_norm_map.items():
738
+ for m in ("weight", "bias"):
739
+ k = "{}.layers.{}.layer_norms.{}.{}".format(name, i, old, m)
740
+ if k in state_dict:
741
+ state_dict[
742
+ "{}.layers.{}.{}.{}".format(name, i, new, m)
743
+ ] = state_dict[k]
744
+ del state_dict[k]
745
+
746
+ version_key = "{}.version".format(name)
747
+ if utils.item(state_dict.get(version_key, torch.Tensor([1]))[0]) <= 2:
748
+ # earlier checkpoints did not normalize after the stack of layers
749
+ self.layer_norm = None
750
+ self.normalize = False
751
+ state_dict[version_key] = torch.Tensor([1])
752
+
753
+ return state_dict
754
+
755
+
756
+ @register_model_architecture(
757
+ "pipeline_parallel_transformer", "transformer_iwslt_de_en_pipeline_parallel"
758
+ )
759
+ def transformer_iwslt_de_en_dist(args):
760
+ transformer_iwslt_de_en(args)
761
+
762
+
763
+ @register_model_architecture(
764
+ "pipeline_parallel_transformer", "transformer_wmt_en_de_big_pipeline_parallel"
765
+ )
766
+ def transformer_wmt_en_de_big_dist(args):
767
+ transformer_wmt_en_de_big(args)
avh-align_core/fairseq/model_parallel/models/roberta/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ from .model import * # noqa
avh-align_core/fairseq/model_parallel/models/roberta/model.py ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+ """
6
+ RoBERTa: A Robustly Optimized BERT Pretraining Approach.
7
+ """
8
+
9
+ import logging
10
+
11
+ import torch
12
+ import torch.nn as nn
13
+ import torch.nn.functional as F
14
+ from fairseq import utils
15
+ from fairseq.model_parallel.models.transformer import ModelParallelTransformerEncoder
16
+ from fairseq.models import register_model, register_model_architecture
17
+ from fairseq.models.roberta import (
18
+ roberta_base_architecture,
19
+ roberta_prenorm_architecture,
20
+ RobertaEncoder,
21
+ RobertaModel,
22
+ )
23
+ from fairseq.modules import LayerNorm
24
+
25
+
26
+ try:
27
+ from fairseq.model_parallel.megatron.mpu import (
28
+ copy_to_model_parallel_region,
29
+ gather_from_model_parallel_region,
30
+ ColumnParallelLinear,
31
+ VocabParallelEmbedding,
32
+ )
33
+
34
+ has_megatron_submodule = True
35
+ except (ImportError, ModuleNotFoundError):
36
+ has_megatron_submodule = False
37
+
38
+ logger = logging.getLogger(__name__)
39
+
40
+
41
+ @register_model("model_parallel_roberta")
42
+ class ModelParallelRobertaModel(RobertaModel):
43
+ def __init__(self, args, encoder):
44
+ super().__init__(args, encoder)
45
+
46
+ self.classification_heads = nn.ModuleDict()
47
+
48
+ @staticmethod
49
+ def add_args(parser):
50
+ RobertaModel.add_args(parser)
51
+ parser.add_argument(
52
+ "--no-final-layer-norm",
53
+ action="store_true",
54
+ help=(
55
+ "don't add final layernorm (only applicable when "
56
+ "--encoder-normalize-before=True"
57
+ ),
58
+ )
59
+
60
+ @classmethod
61
+ def build_model(cls, args, task):
62
+ """Build a new model instance."""
63
+
64
+ # make sure all arguments are present
65
+ base_architecture(args)
66
+
67
+ task.source_dictionary.pad_to_multiple_(args.model_parallel_size * 8)
68
+ task.target_dictionary.pad_to_multiple_(args.model_parallel_size * 8)
69
+
70
+ if not hasattr(args, "max_positions"):
71
+ args.max_positions = args.tokens_per_sample
72
+
73
+ if getattr(args, "untie_weights_roberta", False):
74
+ raise NotImplementedError(
75
+ "--untie-weights-roberta is not supported in model parallel mode"
76
+ )
77
+
78
+ encoder = ModelParallelRobertaEncoder(args, task.source_dictionary)
79
+ return cls(args, encoder)
80
+
81
+ def forward(
82
+ self,
83
+ src_tokens,
84
+ features_only=False,
85
+ return_all_hiddens=False,
86
+ classification_head_name=None,
87
+ **kwargs
88
+ ):
89
+ if classification_head_name is not None:
90
+ features_only = True
91
+
92
+ x, extra = self.encoder(src_tokens, features_only, return_all_hiddens, **kwargs)
93
+
94
+ if classification_head_name is not None:
95
+ x = self.classification_heads[classification_head_name](x)
96
+ return x, extra
97
+
98
+ def register_classification_head(
99
+ self, name, num_classes=None, inner_dim=None, **kwargs
100
+ ):
101
+ """Register a classification head."""
102
+ if name in self.classification_heads:
103
+ prev_num_classes = self.classification_heads[name].out_proj.out_features
104
+ prev_inner_dim = self.classification_heads[name].dense.out_features
105
+ if num_classes != prev_num_classes or inner_dim != prev_inner_dim:
106
+ logger.warning(
107
+ 're-registering head "{}" with num_classes {} (prev: {}) '
108
+ "and inner_dim {} (prev: {})".format(
109
+ name, num_classes, prev_num_classes, inner_dim, prev_inner_dim
110
+ )
111
+ )
112
+ self.classification_heads[name] = ModelParallelRobertaClassificationHead(
113
+ self.args.encoder_embed_dim,
114
+ inner_dim or self.args.encoder_embed_dim,
115
+ num_classes,
116
+ self.args.pooler_activation_fn,
117
+ self.args.pooler_dropout,
118
+ )
119
+
120
+
121
+ class ModelParallelRobertaLMHead(nn.Module):
122
+ """Head for masked language modeling."""
123
+
124
+ def __init__(self, embed_dim, output_dim, activation_fn, weight=None):
125
+ super().__init__()
126
+ self.dense = ColumnParallelLinear(embed_dim, embed_dim, gather_output=True)
127
+ self.activation_fn = utils.get_activation_fn(activation_fn)
128
+ self.layer_norm = LayerNorm(embed_dim)
129
+
130
+ if weight is None:
131
+ weight = nn.Linear(embed_dim, output_dim, bias=False).weight
132
+ self.weight = weight
133
+ self.bias = nn.Parameter(torch.zeros(output_dim))
134
+
135
+ def forward(self, features, masked_tokens=None, **kwargs):
136
+ # Only project the unmasked tokens while training,
137
+ # saves both memory and computation
138
+ if masked_tokens is not None:
139
+ features = features[masked_tokens, :]
140
+
141
+ x = self.dense(features)
142
+ x = self.activation_fn(x)
143
+ x = self.layer_norm(x)
144
+
145
+ x = copy_to_model_parallel_region(x)
146
+ # project back to size of vocabulary with bias
147
+ x = F.linear(x, self.weight)
148
+ x = gather_from_model_parallel_region(x).contiguous()
149
+ x = x + self.bias
150
+ return x
151
+
152
+
153
+ class ModelParallelRobertaClassificationHead(nn.Module):
154
+ """Head for sentence-level classification tasks."""
155
+
156
+ def __init__(
157
+ self, input_dim, inner_dim, num_classes, activation_fn, pooler_dropout
158
+ ):
159
+ super().__init__()
160
+ self.dense = ColumnParallelLinear(input_dim, inner_dim, gather_output=True)
161
+ self.activation_fn = utils.get_activation_fn(activation_fn)
162
+ self.dropout = nn.Dropout(p=pooler_dropout)
163
+ self.out_proj = nn.Linear(inner_dim, num_classes)
164
+
165
+ def forward(self, features, **kwargs):
166
+ x = features[:, 0, :] # take <s> token (equiv. to [CLS])
167
+ x = self.dropout(x)
168
+ x = self.dense(x)
169
+ x = self.activation_fn(x)
170
+ x = self.dropout(x)
171
+ x = self.out_proj(x)
172
+ return x
173
+
174
+
175
+ class ModelParallelRobertaEncoder(RobertaEncoder):
176
+ """RoBERTa encoder."""
177
+
178
+ def __init__(self, args, dictionary):
179
+ super().__init__(args, dictionary)
180
+ assert not self.args.untie_weights_roberta
181
+
182
+ def build_embedding(self, vocab_size, embedding_dim, padding_idx):
183
+ return VocabParallelEmbedding(vocab_size, embedding_dim, padding_idx)
184
+
185
+ def build_encoder(self, args, dictionary, embed_tokens):
186
+ return ModelParallelTransformerEncoder(args, dictionary, embed_tokens)
187
+
188
+ def build_lm_head(self, embed_dim, output_dim, activation_fn, weight):
189
+ return ModelParallelRobertaLMHead(embed_dim, output_dim, activation_fn, weight)
190
+
191
+
192
+ @register_model_architecture("model_parallel_roberta", "model_parallel_roberta")
193
+ def base_architecture(args):
194
+ args.no_final_layer_norm = getattr(args, "no_final_layer_norm", False)
195
+ # model parallel RoBERTa defaults to "Pre-LN" formulation
196
+ roberta_prenorm_architecture(args)
197
+
198
+
199
+ # earlier versions of model parallel RoBERTa removed the final layer norm
200
+ @register_model_architecture("model_parallel_roberta", "model_parallel_roberta_v1")
201
+ def model_parallel_roberta_v1_architecture(args):
202
+ args.no_final_layer_norm = getattr(args, "no_final_layer_norm", True)
203
+ base_architecture(args)
204
+
205
+
206
+ @register_model_architecture(
207
+ "model_parallel_roberta", "model_parallel_roberta_postnorm"
208
+ )
209
+ def model_parallel_roberta_postnorm_architecture(args):
210
+ # the original BERT/RoBERTa uses the "Post-LN" formulation
211
+ roberta_base_architecture(args)
212
+
213
+
214
+ @register_model_architecture("model_parallel_roberta", "model_parallel_roberta_base")
215
+ def model_parallel_roberta_base_architecture(args):
216
+ base_architecture(args)
217
+
218
+
219
+ @register_model_architecture("model_parallel_roberta", "model_parallel_roberta_large")
220
+ def model_parallel_roberta_large_architecture(args):
221
+ args.encoder_layers = getattr(args, "encoder_layers", 24)
222
+ args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024)
223
+ args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 4096)
224
+ args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 16)
225
+ base_architecture(args)
avh-align_core/fairseq/model_parallel/models/transformer.py ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import logging
7
+
8
+ import torch.nn as nn
9
+ from fairseq.model_parallel.modules import (
10
+ ModelParallelTransformerDecoderLayer,
11
+ ModelParallelTransformerEncoderLayer,
12
+ )
13
+ from fairseq.models import register_model
14
+ from fairseq.models.transformer import (
15
+ TransformerDecoder,
16
+ TransformerEncoder,
17
+ TransformerModel,
18
+ )
19
+
20
+
21
+ try:
22
+ from fairseq.model_parallel.megatron.mpu import (
23
+ copy_to_model_parallel_region,
24
+ gather_from_model_parallel_region,
25
+ VocabParallelEmbedding,
26
+ )
27
+
28
+ has_megatron_submodule = True
29
+ except (ImportError, ModuleNotFoundError):
30
+ has_megatron_submodule = False
31
+
32
+
33
+ logger = logging.getLogger(__name__)
34
+
35
+
36
+ @register_model("model_parallel_transformer")
37
+ class ModelParallelTransformerModel(TransformerModel):
38
+ """
39
+ Model parallel Transformer model.
40
+ """
41
+
42
+ @classmethod
43
+ def build_embedding(cls, args, dictionary, embed_dim, path=None):
44
+ if not has_megatron_submodule:
45
+ raise ImportError(
46
+ "\n\nPlease install the megatron submodule:"
47
+ "\n\n git submodule update --init "
48
+ "fairseq/model_parallel/megatron"
49
+ )
50
+ dictionary.pad_to_multiple_(args.model_parallel_size * 8)
51
+ num_embeddings = len(dictionary)
52
+ padding_idx = dictionary.pad()
53
+
54
+ def _vocab_init(tensor, **kwargs):
55
+ nn.init.normal_(tensor, mean=0, std=num_embeddings ** -0.5)
56
+ nn.init.constant_(tensor[1], 0)
57
+
58
+ emb = VocabParallelEmbedding(
59
+ num_embeddings, embed_dim, padding_idx, init_method=_vocab_init
60
+ )
61
+ # if provided, load from preloaded dictionaries
62
+ if path:
63
+ raise NotImplementedError(
64
+ "Loading of embedding from path is not supported for model parallel"
65
+ )
66
+ return emb
67
+
68
+ @classmethod
69
+ def build_encoder(cls, args, src_dict, embed_tokens):
70
+ return ModelParallelTransformerEncoder(args, src_dict, embed_tokens)
71
+
72
+ @classmethod
73
+ def build_decoder(cls, args, tgt_dict, embed_tokens):
74
+ return ModelParallelTransformerDecoder(
75
+ args,
76
+ tgt_dict,
77
+ embed_tokens,
78
+ no_encoder_attn=getattr(args, "no_cross_attention", False),
79
+ )
80
+
81
+
82
+ class ModelParallelTransformerEncoder(TransformerEncoder):
83
+ """
84
+ Model parallel Transformer encoder consisting of *args.encoder_layers* layers. Each layer
85
+ is a :class:`ModelParallelTransformerEncoderLayer`.
86
+ """
87
+
88
+ def __init__(self, args, dictionary, embed_tokens):
89
+ super().__init__(args, dictionary, embed_tokens)
90
+
91
+ if args.no_final_layer_norm:
92
+ self.layer_norm = None
93
+
94
+ def build_encoder_layer(self, args):
95
+ return ModelParallelTransformerEncoderLayer(args)
96
+
97
+
98
+ class ModelParallelTransformerDecoder(TransformerDecoder):
99
+ """
100
+ Model Parallel Transformer decoder consisting of *args.decoder_layers* layers. Each layer
101
+ is a :class:`ModelParallelTransformerDecoderLayer`.
102
+ """
103
+
104
+ def build_decoder_layer(self, args, no_encoder_attn=False):
105
+ return ModelParallelTransformerDecoderLayer(args, no_encoder_attn)
106
+
107
+ def output_layer(self, features, **kwargs):
108
+ """Project features to the vocabulary size."""
109
+ if not self.share_input_output_embed:
110
+ raise NotImplementedError(
111
+ "Model parallel training currently requires --share-decoder-input-output-embed"
112
+ )
113
+
114
+ features = copy_to_model_parallel_region(features)
115
+
116
+ # project back to size of vocabulary
117
+ x = self.output_projection(features)
118
+
119
+ if getattr(self.args, "criterion") != "vocab_parallel_cross_entropy":
120
+ x = gather_from_model_parallel_region(x).contiguous()
121
+ return x
avh-align_core/fairseq/model_parallel/models/transformer_lm.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import torch.nn as nn
7
+ from fairseq.model_parallel.models.transformer import ModelParallelTransformerDecoder
8
+ from fairseq.models import register_model, register_model_architecture
9
+ from fairseq.models.transformer_lm import TransformerLanguageModel
10
+
11
+
12
+ try:
13
+ from fairseq.model_parallel.megatron.mpu import VocabParallelEmbedding
14
+
15
+ has_megatron_submodule = True
16
+ except (ImportError, ModuleNotFoundError):
17
+ has_megatron_submodule = False
18
+
19
+
20
+ DEFAULT_MAX_TARGET_POSITIONS = 1024
21
+
22
+
23
+ @register_model("model_parallel_transformer_lm")
24
+ class ModelParallelTransformerLanguageModel(TransformerLanguageModel):
25
+
26
+ @staticmethod
27
+ def add_args(parser):
28
+ TransformerLanguageModel.add_args(parser)
29
+
30
+ @classmethod
31
+ def build_model(cls, args, task):
32
+ """Build a new model instance."""
33
+ if not has_megatron_submodule:
34
+ raise ImportError(
35
+ "\n\nPlease install the megatron submodule:"
36
+ "\n\n git submodule update --init "
37
+ "fairseq/model_parallel/megatron"
38
+ )
39
+
40
+ # make sure all arguments are present in older models
41
+ base_lm_architecture(args)
42
+
43
+ task.source_dictionary.pad_to_multiple_(args.model_parallel_size * 8)
44
+ task.target_dictionary.pad_to_multiple_(args.model_parallel_size * 8)
45
+
46
+ if args.decoder_layers_to_keep:
47
+ args.decoder_layers = len(args.decoder_layers_to_keep.split(","))
48
+
49
+ if getattr(args, "max_target_positions", None) is None:
50
+ args.max_target_positions = getattr(
51
+ args, "tokens_per_sample", DEFAULT_MAX_TARGET_POSITIONS
52
+ )
53
+
54
+ if args.character_embeddings:
55
+ raise NotImplementedError(
56
+ "Character embeddings is not supported for model parallel"
57
+ )
58
+ elif args.adaptive_input:
59
+ raise NotImplementedError(
60
+ "Adaptive input is not supported for model parallel"
61
+ )
62
+ else:
63
+ embed_tokens = cls.build_embedding(
64
+ args, task.source_dictionary, args.decoder_input_dim
65
+ )
66
+
67
+ decoder = ModelParallelTransformerDecoder(
68
+ args,
69
+ task.target_dictionary,
70
+ embed_tokens,
71
+ no_encoder_attn=True,
72
+ )
73
+ return cls(decoder)
74
+
75
+ @staticmethod
76
+ def add_args(parser):
77
+ TransformerLanguageModel.add_args(parser)
78
+
79
+ @classmethod
80
+ def build_embedding(cls, args, dictionary, embed_dim, path=None):
81
+ def _vocab_init(tensor, **kwargs):
82
+ nn.init.normal_(tensor, mean=0, std=embed_dim ** -0.5)
83
+ nn.init.constant_(tensor[1], 0)
84
+
85
+ embed_tokens = VocabParallelEmbedding(
86
+ len(dictionary), embed_dim, dictionary.pad(), init_method=_vocab_init
87
+ )
88
+ return embed_tokens
89
+
90
+
91
+ def base_lm_architecture(args):
92
+ # backward compatibility for older model checkpoints
93
+ if hasattr(args, "no_tie_adaptive_proj"):
94
+ # previous models defined --no-tie-adaptive-proj, so use the existence of
95
+ # that option to determine if this is an "old" model checkpoint
96
+ args.no_decoder_final_norm = True # old models always set this to True
97
+ if args.no_tie_adaptive_proj is False:
98
+ args.tie_adaptive_proj = True
99
+ if hasattr(args, "decoder_final_norm"):
100
+ args.no_decoder_final_norm = not args.decoder_final_norm
101
+
102
+ args.activation_fn = getattr(args, "activation_fn", "relu")
103
+ args.dropout = getattr(args, "dropout", 0.1)
104
+ args.attention_dropout = getattr(args, "attention_dropout", 0.0)
105
+ args.activation_dropout = getattr(args, "activation_dropout", 0.0)
106
+ args.relu_dropout = getattr(args, "relu_dropout", 0.0)
107
+ args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 512)
108
+ args.decoder_output_dim = getattr(
109
+ args, "decoder_output_dim", args.decoder_embed_dim
110
+ )
111
+ args.decoder_input_dim = getattr(args, "decoder_input_dim", args.decoder_embed_dim)
112
+ args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 2048)
113
+ args.decoder_layers = getattr(args, "decoder_layers", 6)
114
+ args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 8)
115
+ # Model training is not stable without this
116
+ args.decoder_normalize_before = True
117
+ args.no_decoder_final_norm = getattr(args, "no_decoder_final_norm", False)
118
+ args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None)
119
+ args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0)
120
+ args.adaptive_softmax_factor = getattr(args, "adaptive_softmax_factor", 4)
121
+ args.no_token_positional_embeddings = getattr(
122
+ args, "no_token_positional_embeddings", False
123
+ )
124
+ args.share_decoder_input_output_embed = getattr(
125
+ args, "share_decoder_input_output_embed", False
126
+ )
127
+ args.character_embeddings = getattr(args, "character_embeddings", False)
128
+ args.character_filters = getattr(
129
+ args,
130
+ "character_filters",
131
+ "[(1, 64), (2, 128), (3, 192), (4, 256), (5, 256), (6, 256), (7, 256)]",
132
+ )
133
+ args.character_embedding_dim = getattr(args, "character_embedding_dim", 4)
134
+ args.char_embedder_highway_layers = getattr(args, "char_embedder_highway_layers", 2)
135
+ args.adaptive_input = getattr(args, "adaptive_input", False)
136
+ args.adaptive_input_factor = getattr(args, "adaptive_input_factor", 4)
137
+ args.adaptive_input_cutoff = getattr(args, "adaptive_input_cutoff", None)
138
+ args.tie_adaptive_weights = getattr(args, "tie_adaptive_weights", False)
139
+ args.tie_adaptive_proj = getattr(args, "tie_adaptive_proj", False)
140
+ args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False)
141
+ args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0.0)
142
+ args.decoder_layers_to_keep = getattr(args, "decoder_layers_to_keep", None)
143
+ args.layernorm_embedding = getattr(args, "layernorm_embedding", False)
144
+ args.no_scale_embedding = getattr(args, "no_scale_embedding", False)
145
+ args.quant_noise_pq = getattr(args, "quant_noise_pq", 0.0)
146
+ args.quant_noise_pq_block_size = getattr(args, "quant_noise_pq_block_size", 8)
147
+ args.quant_noise_scalar = getattr(args, "quant_noise_scalar", 0.0)
148
+ args.add_bos_token = getattr(args, "add_bos_token", False)
149
+
150
+
151
+ @register_model_architecture("model_parallel_transformer_lm", "transformer_lm_megatron")
152
+ def transformer_lm_megatron(args):
153
+ args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 3072)
154
+ args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 3072 * 4)
155
+ args.decoder_layers = getattr(args, "decoder_layers", 72)
156
+ args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 32)
157
+ args.dropout = getattr(args, "dropout", 0.1)
158
+ args.attention_dropout = getattr(args, "attention_dropout", 0.1)
159
+ args.activation_fn = getattr(args, "activation_fn", "gelu")
160
+ base_lm_architecture(args)
161
+
162
+
163
+ @register_model_architecture(
164
+ "model_parallel_transformer_lm", "transformer_lm_megatron_11b"
165
+ )
166
+ def transformer_lm_megatron_11b(args):
167
+ args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 3072)
168
+ args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 3072 * 6)
169
+ args.decoder_layers = getattr(args, "decoder_layers", 72)
170
+ args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 32)
171
+ args.dropout = getattr(args, "dropout", 0.1)
172
+ args.attention_dropout = getattr(args, "attention_dropout", 0.1)
173
+ args.activation_fn = getattr(args, "activation_fn", "gelu")
174
+ base_lm_architecture(args)
avh-align_core/fairseq/model_parallel/modules/__init__.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+ """isort:skip_file"""
6
+
7
+ from .multihead_attention import ModelParallelMultiheadAttention
8
+ from .transformer_layer import (
9
+ ModelParallelTransformerEncoderLayer,
10
+ ModelParallelTransformerDecoderLayer,
11
+ )
12
+
13
+ __all__ = [
14
+ "ModelParallelMultiheadAttention",
15
+ "ModelParallelTransformerEncoderLayer",
16
+ "ModelParallelTransformerDecoderLayer",
17
+ ]
avh-align_core/fairseq/model_parallel/modules/multihead_attention.py ADDED
@@ -0,0 +1,349 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ from typing import Dict, Optional, Tuple
7
+
8
+ import torch
9
+ import torch.nn.functional as F
10
+ from fairseq import utils
11
+ from fairseq.incremental_decoding_utils import with_incremental_state
12
+ from fairseq.modules.fairseq_dropout import FairseqDropout
13
+ from torch import Tensor, nn
14
+
15
+
16
+ try:
17
+ from fairseq.model_parallel.megatron.mpu import (
18
+ get_cuda_rng_tracker,
19
+ get_model_parallel_world_size,
20
+ ColumnParallelLinear,
21
+ RowParallelLinear,
22
+ )
23
+
24
+ has_megatron_submodule = True
25
+ except (ImportError, ModuleNotFoundError):
26
+ has_megatron_submodule = False
27
+
28
+
29
+ @with_incremental_state
30
+ class ModelParallelMultiheadAttention(nn.Module):
31
+ """Model parallel Multi-headed attention.
32
+ This performs the Multi-headed attention over multiple gpus.
33
+
34
+ See "Megatron-LM: https://arxiv.org/pdf/1909.08053.pdf" for more details.
35
+ """
36
+
37
+ def __init__(
38
+ self,
39
+ embed_dim,
40
+ num_heads,
41
+ kdim=None,
42
+ vdim=None,
43
+ dropout=0.0,
44
+ bias=True,
45
+ self_attention=False,
46
+ encoder_decoder_attention=False,
47
+ ):
48
+ super().__init__()
49
+ if not has_megatron_submodule:
50
+ raise ImportError(
51
+ "\n\nPlease install the megatron submodule:"
52
+ "\n\n git submodule update --init "
53
+ "fairseq/model_parallel/megatron"
54
+ )
55
+ self.embed_dim = embed_dim
56
+ self.kdim = kdim if kdim is not None else embed_dim
57
+ self.vdim = vdim if vdim is not None else embed_dim
58
+ self.qkv_same_dim = self.kdim == embed_dim and self.vdim == embed_dim
59
+
60
+ self.model_parallel_size = get_model_parallel_world_size()
61
+
62
+ self.num_heads_partition = num_heads // self.model_parallel_size
63
+ assert (
64
+ self.num_heads_partition * self.model_parallel_size == num_heads
65
+ ), "Number of heads must be divisible by model parallel size"
66
+
67
+ self.dropout_module = FairseqDropout(
68
+ dropout, module_name=self.__class__.__name__
69
+ )
70
+ self.head_dim = embed_dim // num_heads
71
+ assert (
72
+ self.head_dim * num_heads == self.embed_dim
73
+ ), "embed_dim must be divisible by num_heads"
74
+ self.scaling = self.head_dim ** -0.5
75
+
76
+ self.self_attention = self_attention
77
+ self.encoder_decoder_attention = encoder_decoder_attention
78
+
79
+ assert (
80
+ not self.self_attention or self.qkv_same_dim
81
+ ), "Self-attention requires query, key and value to be of the same size"
82
+
83
+ self.k_proj = ColumnParallelLinear(
84
+ self.kdim, embed_dim, bias=bias, gather_output=False
85
+ )
86
+ self.v_proj = ColumnParallelLinear(
87
+ self.vdim, embed_dim, bias=bias, gather_output=False
88
+ )
89
+ self.q_proj = ColumnParallelLinear(
90
+ embed_dim, embed_dim, bias=bias, gather_output=False
91
+ )
92
+ self.out_proj = RowParallelLinear(
93
+ embed_dim, embed_dim, bias=bias, input_is_parallel=True
94
+ )
95
+
96
+ def forward(
97
+ self,
98
+ query,
99
+ key: Optional[Tensor],
100
+ value: Optional[Tensor],
101
+ key_padding_mask: Optional[Tensor] = None,
102
+ incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None,
103
+ static_kv: bool = False,
104
+ attn_mask: Optional[Tensor] = None,
105
+ **unused_kwargs,
106
+ ) -> Tuple[Tensor, Optional[Tensor]]:
107
+ """Input shape: Time x Batch x Channel
108
+
109
+ Args:
110
+ key_padding_mask (ByteTensor, optional): mask to exclude
111
+ keys that are pads, of shape `(batch, src_len)`, where
112
+ padding elements are indicated by 1s.
113
+ attn_mask (ByteTensor, optional): typically used to
114
+ implement causal attention, where the mask prevents the
115
+ attention from looking forward in time (default: None).
116
+ """
117
+ tgt_len, bsz, embed_dim = query.size()
118
+ assert embed_dim == self.embed_dim
119
+ assert list(query.size()) == [tgt_len, bsz, embed_dim]
120
+
121
+ is_tpu = query.device.type == "xla"
122
+
123
+ if incremental_state is not None:
124
+ saved_state = self._get_input_buffer(incremental_state)
125
+ if saved_state is not None and "prev_key" in saved_state:
126
+ # previous time steps are cached - no need to recompute
127
+ # key and value if they are static
128
+ if static_kv:
129
+ assert self.encoder_decoder_attention and not self.self_attention
130
+ key = value = None
131
+ else:
132
+ saved_state = None
133
+
134
+ if self.self_attention:
135
+ q = self.q_proj(query)
136
+ k = self.k_proj(query)
137
+ v = self.v_proj(query)
138
+ elif self.encoder_decoder_attention:
139
+ # encoder-decoder attention
140
+ q = self.q_proj(query)
141
+ if key is None:
142
+ assert value is None
143
+ k = v = None
144
+ else:
145
+ k = self.k_proj(key)
146
+ v = self.v_proj(key)
147
+
148
+ else:
149
+ assert key is not None and value is not None
150
+ q = self.q_proj(query)
151
+ k = self.k_proj(key)
152
+ v = self.v_proj(value)
153
+ q *= self.scaling
154
+
155
+ q = (
156
+ q.contiguous()
157
+ .view(tgt_len, bsz * self.num_heads_partition, self.head_dim)
158
+ .transpose(0, 1)
159
+ )
160
+ if k is not None:
161
+ k = (
162
+ k.contiguous()
163
+ .view(-1, bsz * self.num_heads_partition, self.head_dim)
164
+ .transpose(0, 1)
165
+ )
166
+ if v is not None:
167
+ v = (
168
+ v.contiguous()
169
+ .view(-1, bsz * self.num_heads_partition, self.head_dim)
170
+ .transpose(0, 1)
171
+ )
172
+
173
+ if saved_state is not None:
174
+ # saved states are stored with shape (bsz, num_heads_partition, seq_len, head_dim)
175
+ if "prev_key" in saved_state:
176
+ _prev_key = saved_state["prev_key"]
177
+ assert _prev_key is not None
178
+ prev_key = _prev_key.view(
179
+ bsz * self.num_heads_partition, -1, self.head_dim
180
+ )
181
+ if static_kv:
182
+ k = prev_key
183
+ else:
184
+ assert k is not None
185
+ k = torch.cat([prev_key, k], dim=1)
186
+ if "prev_value" in saved_state:
187
+ _prev_value = saved_state["prev_value"]
188
+ assert _prev_value is not None
189
+ prev_value = _prev_value.view(
190
+ bsz * self.num_heads_partition, -1, self.head_dim
191
+ )
192
+ if static_kv:
193
+ v = prev_value
194
+ else:
195
+ assert v is not None
196
+ v = torch.cat([prev_value, v], dim=1)
197
+ prev_key_padding_mask: Optional[Tensor] = None
198
+ if "prev_key_padding_mask" in saved_state:
199
+ prev_key_padding_mask = saved_state["prev_key_padding_mask"]
200
+ assert k is not None and v is not None
201
+ key_padding_mask = (
202
+ ModelParallelMultiheadAttention._append_prev_key_padding_mask(
203
+ key_padding_mask=key_padding_mask,
204
+ prev_key_padding_mask=prev_key_padding_mask,
205
+ batch_size=bsz,
206
+ src_len=k.size(1),
207
+ static_kv=static_kv,
208
+ )
209
+ )
210
+
211
+ saved_state["prev_key"] = k.view(
212
+ bsz, self.num_heads_partition, -1, self.head_dim
213
+ )
214
+ saved_state["prev_value"] = v.view(
215
+ bsz, self.num_heads_partition, -1, self.head_dim
216
+ )
217
+ saved_state["prev_key_padding_mask"] = key_padding_mask
218
+ # In this branch incremental_state is never None
219
+ assert incremental_state is not None
220
+ incremental_state = self._set_input_buffer(incremental_state, saved_state)
221
+ assert k is not None
222
+ src_len = k.size(1)
223
+
224
+ # This is part of a workaround to get around fork/join parallelism
225
+ # not supporting Optional types.
226
+ if key_padding_mask is not None and key_padding_mask.dim() == 0:
227
+ key_padding_mask = None
228
+
229
+ if key_padding_mask is not None:
230
+ assert key_padding_mask.size(0) == bsz
231
+ assert key_padding_mask.size(1) == src_len
232
+
233
+ attn_weights = torch.bmm(q, k.transpose(1, 2))
234
+
235
+ assert list(attn_weights.size()) == [
236
+ bsz * self.num_heads_partition,
237
+ tgt_len,
238
+ src_len,
239
+ ]
240
+
241
+ if attn_mask is not None:
242
+ attn_mask = attn_mask.unsqueeze(0)
243
+ attn_weights += attn_mask
244
+
245
+ if key_padding_mask is not None:
246
+ # don't attend to padding symbols
247
+ attn_weights = attn_weights.view(
248
+ bsz, self.num_heads_partition, tgt_len, src_len
249
+ )
250
+ if not is_tpu:
251
+ attn_weights = attn_weights.masked_fill(
252
+ key_padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool),
253
+ float("-inf"),
254
+ )
255
+ else:
256
+ attn_weights = attn_weights.transpose(0, 2)
257
+ attn_weights = attn_weights.masked_fill(key_padding_mask, float("-inf"))
258
+ attn_weights = attn_weights.transpose(0, 2)
259
+ attn_weights = attn_weights.view(
260
+ bsz * self.num_heads_partition, tgt_len, src_len
261
+ )
262
+
263
+ attn_weights_float = utils.softmax(attn_weights, dim=-1)
264
+ attn_weights = attn_weights_float.type_as(attn_weights)
265
+
266
+ with get_cuda_rng_tracker().fork():
267
+ attn_probs = self.dropout_module(attn_weights)
268
+
269
+ assert v is not None
270
+ attn = torch.bmm(attn_probs, v)
271
+ assert list(attn.size()) == [
272
+ bsz * self.num_heads_partition,
273
+ tgt_len,
274
+ self.head_dim,
275
+ ]
276
+ embed_dim_partition = embed_dim // self.model_parallel_size
277
+ attn = attn.transpose(0, 1).contiguous().view(tgt_len, bsz, embed_dim_partition)
278
+ attn = self.out_proj(attn)
279
+ # return attn_weights None to keep the return type same as single gpu multihead attention
280
+ # This will be deprecated.
281
+ attn_weights: Optional[Tensor] = None
282
+
283
+ return attn, attn_weights
284
+
285
+ @staticmethod
286
+ def _append_prev_key_padding_mask(
287
+ key_padding_mask: Optional[Tensor],
288
+ prev_key_padding_mask: Optional[Tensor],
289
+ batch_size: int,
290
+ src_len: int,
291
+ static_kv: bool,
292
+ ) -> Optional[Tensor]:
293
+ # saved key padding masks have shape (bsz, seq_len)
294
+ if prev_key_padding_mask is not None and static_kv:
295
+ new_key_padding_mask = prev_key_padding_mask
296
+ elif prev_key_padding_mask is not None and key_padding_mask is not None:
297
+ new_key_padding_mask = torch.cat(
298
+ [prev_key_padding_mask.float(), key_padding_mask.float()], dim=1
299
+ )
300
+ # During incremental decoding, as the padding token enters and
301
+ # leaves the frame, there will be a time when prev or current
302
+ # is None
303
+ elif prev_key_padding_mask is not None:
304
+
305
+ filler = torch.zeros(batch_size, src_len - prev_key_padding_mask.size(1))
306
+ if prev_key_padding_mask.is_cuda:
307
+ filler = filler.cuda()
308
+ new_key_padding_mask = torch.cat(
309
+ [prev_key_padding_mask.float(), filler.float()], dim=1
310
+ )
311
+ elif key_padding_mask is not None:
312
+ filler = torch.zeros(batch_size, src_len - key_padding_mask.size(1))
313
+ if key_padding_mask.is_cuda:
314
+ filler = filler.cuda()
315
+ new_key_padding_mask = torch.cat(
316
+ [filler.float(), key_padding_mask.float()], dim=1
317
+ )
318
+ else:
319
+ new_key_padding_mask = prev_key_padding_mask
320
+ return new_key_padding_mask
321
+
322
+ def reorder_incremental_state(
323
+ self, incremental_state: Dict[str, Dict[str, Optional[Tensor]]], new_order
324
+ ):
325
+ """Reorder buffered internal state (for incremental generation)."""
326
+ input_buffer = self._get_input_buffer(incremental_state)
327
+ if input_buffer is not None:
328
+ for k in input_buffer.keys():
329
+ if input_buffer[k] is not None:
330
+ input_buffer[k] = input_buffer[k].index_select(0, new_order)
331
+ incremental_state = self._set_input_buffer(incremental_state, input_buffer)
332
+ return incremental_state
333
+
334
+ def _get_input_buffer(
335
+ self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]]
336
+ ) -> Dict[str, Optional[Tensor]]:
337
+ result = self.get_incremental_state(incremental_state, "attn_state")
338
+ if result is not None:
339
+ return result
340
+ else:
341
+ empty_result: Dict[str, Optional[Tensor]] = {}
342
+ return empty_result
343
+
344
+ def _set_input_buffer(
345
+ self,
346
+ incremental_state: Dict[str, Dict[str, Optional[Tensor]]],
347
+ buffer: Dict[str, Optional[Tensor]],
348
+ ):
349
+ return self.set_incremental_state(incremental_state, "attn_state", buffer)
avh-align_core/fairseq/model_parallel/modules/transformer_layer.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ from fairseq.model_parallel.modules import ModelParallelMultiheadAttention
7
+ from fairseq.modules import TransformerDecoderLayer, TransformerEncoderLayer
8
+
9
+
10
+ try:
11
+ from fairseq.model_parallel.megatron.mpu import (
12
+ ColumnParallelLinear,
13
+ RowParallelLinear,
14
+ )
15
+
16
+ has_megatron_submodule = True
17
+ except (ImportError, ModuleNotFoundError):
18
+ has_megatron_submodule = False
19
+
20
+
21
+ class ModelParallelTransformerEncoderLayer(TransformerEncoderLayer):
22
+ """Encoder layer block over multiple gpus.
23
+
24
+ See "Megatron-LM: https://arxiv.org/pdf/1909.08053.pdf" for more details.
25
+ """
26
+
27
+ def build_fc1(self, input_dim, output_dim, q_noise, qn_block_size):
28
+ if q_noise > 0:
29
+ raise NotImplementedError
30
+ return ColumnParallelLinear(input_dim, output_dim, gather_output=False)
31
+
32
+ def build_fc2(self, input_dim, output_dim, q_noise, qn_block_size):
33
+ if q_noise > 0:
34
+ raise NotImplementedError
35
+ return RowParallelLinear(input_dim, output_dim, input_is_parallel=True)
36
+
37
+ def build_self_attention(self, embed_dim, args, **unused_kwargs):
38
+ return ModelParallelMultiheadAttention(
39
+ embed_dim,
40
+ args.encoder_attention_heads,
41
+ dropout=args.attention_dropout,
42
+ self_attention=True,
43
+ )
44
+
45
+
46
+ class ModelParallelTransformerDecoderLayer(TransformerDecoderLayer):
47
+ """Decoder layer block.
48
+
49
+ See "Megatron-LM: https://arxiv.org/pdf/1909.08053.pdf" for more details.
50
+ """
51
+
52
+ def build_fc1(self, input_dim, output_dim, q_noise, qn_block_size):
53
+ if q_noise > 0:
54
+ raise NotImplementedError
55
+ return ColumnParallelLinear(input_dim, output_dim, gather_output=False)
56
+
57
+ def build_fc2(self, input_dim, output_dim, q_noise, qn_block_size):
58
+ if q_noise > 0:
59
+ raise NotImplementedError
60
+ return RowParallelLinear(input_dim, output_dim, input_is_parallel=True)
61
+
62
+ def build_self_attention(self, embed_dim, args, **unused_kwargs):
63
+ return ModelParallelMultiheadAttention(
64
+ embed_dim=embed_dim,
65
+ num_heads=args.decoder_attention_heads,
66
+ dropout=args.attention_dropout,
67
+ self_attention=not getattr(args, "cross_self_attention", False),
68
+ )
69
+
70
+ def build_encoder_attention(self, embed_dim, args, **unused_kwargs):
71
+ return ModelParallelMultiheadAttention(
72
+ embed_dim=embed_dim,
73
+ num_heads=args.decoder_attention_heads,
74
+ kdim=getattr(args, "encoder_embed_dim", None),
75
+ vdim=getattr(args, "encoder_embed_dim", None),
76
+ dropout=args.attention_dropout,
77
+ encoder_decoder_attention=True,
78
+ )
avh-align_core/fairseq/models/__init__.py ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+ """isort:skip_file"""
6
+
7
+ import argparse
8
+ import importlib
9
+ import os
10
+
11
+ from fairseq.dataclass import FairseqDataclass
12
+ from fairseq.dataclass.utils import merge_with_parent, populate_dataclass
13
+ from hydra.core.config_store import ConfigStore
14
+
15
+ from .composite_encoder import CompositeEncoder
16
+ from .distributed_fairseq_model import DistributedFairseqModel
17
+ from .fairseq_decoder import FairseqDecoder
18
+ from .fairseq_encoder import FairseqEncoder
19
+ from .fairseq_incremental_decoder import FairseqIncrementalDecoder
20
+ from .fairseq_model import (
21
+ BaseFairseqModel,
22
+ FairseqEncoderDecoderModel,
23
+ FairseqEncoderModel,
24
+ FairseqLanguageModel,
25
+ FairseqModel,
26
+ FairseqMultiModel,
27
+ )
28
+
29
+
30
+ MODEL_REGISTRY = {}
31
+ MODEL_DATACLASS_REGISTRY = {}
32
+ ARCH_MODEL_REGISTRY = {}
33
+ ARCH_MODEL_NAME_REGISTRY = {}
34
+ ARCH_MODEL_INV_REGISTRY = {}
35
+ ARCH_CONFIG_REGISTRY = {}
36
+
37
+
38
+ __all__ = [
39
+ "BaseFairseqModel",
40
+ "CompositeEncoder",
41
+ "DistributedFairseqModel",
42
+ "FairseqDecoder",
43
+ "FairseqEncoder",
44
+ "FairseqEncoderDecoderModel",
45
+ "FairseqEncoderModel",
46
+ "FairseqIncrementalDecoder",
47
+ "FairseqLanguageModel",
48
+ "FairseqModel",
49
+ "FairseqMultiModel",
50
+ ]
51
+
52
+
53
+ def build_model(cfg: FairseqDataclass, task):
54
+
55
+ model = None
56
+ model_type = getattr(cfg, "_name", None) or getattr(cfg, "arch", None)
57
+
58
+ if not model_type and len(cfg) == 1:
59
+ # this is hit if config object is nested in directory that is named after model type
60
+
61
+ model_type = next(iter(cfg))
62
+ if model_type in MODEL_DATACLASS_REGISTRY:
63
+ cfg = cfg[model_type]
64
+ else:
65
+ raise Exception(
66
+ "Could not infer model type from directory. Please add _name field to indicate model type. "
67
+ "Available models: "
68
+ + str(MODEL_DATACLASS_REGISTRY.keys())
69
+ + " Requested model type: "
70
+ + model_type
71
+ )
72
+
73
+ if model_type in ARCH_MODEL_REGISTRY:
74
+ # case 1: legacy models
75
+ model = ARCH_MODEL_REGISTRY[model_type]
76
+ elif model_type in MODEL_DATACLASS_REGISTRY:
77
+ # case 2: config-driven models
78
+ model = MODEL_REGISTRY[model_type]
79
+
80
+ if model_type in MODEL_DATACLASS_REGISTRY:
81
+ # set defaults from dataclass. note that arch name and model name can be the same
82
+ dc = MODEL_DATACLASS_REGISTRY[model_type]
83
+ if isinstance(cfg, argparse.Namespace):
84
+ cfg = populate_dataclass(dc(), cfg)
85
+ else:
86
+ cfg = merge_with_parent(dc(), cfg)
87
+
88
+ assert model is not None, (
89
+ f"Could not infer model type from {cfg}. "
90
+ f"Available models: "
91
+ + str(MODEL_DATACLASS_REGISTRY.keys())
92
+ + " Requested model type: "
93
+ + model_type
94
+ )
95
+
96
+ return model.build_model(cfg, task)
97
+
98
+
99
+ def register_model(name, dataclass=None):
100
+ """
101
+ New model types can be added to fairseq with the :func:`register_model`
102
+ function decorator.
103
+
104
+ For example::
105
+
106
+ @register_model('lstm')
107
+ class LSTM(FairseqEncoderDecoderModel):
108
+ (...)
109
+
110
+ .. note:: All models must implement the :class:`BaseFairseqModel` interface.
111
+ Typically you will extend :class:`FairseqEncoderDecoderModel` for
112
+ sequence-to-sequence tasks or :class:`FairseqLanguageModel` for
113
+ language modeling tasks.
114
+
115
+ Args:
116
+ name (str): the name of the model
117
+ """
118
+
119
+ def register_model_cls(cls):
120
+ if name in MODEL_REGISTRY:
121
+ raise ValueError("Cannot register duplicate model ({})".format(name))
122
+ if not issubclass(cls, BaseFairseqModel):
123
+ raise ValueError(
124
+ "Model ({}: {}) must extend BaseFairseqModel".format(name, cls.__name__)
125
+ )
126
+ MODEL_REGISTRY[name] = cls
127
+ if dataclass is not None and not issubclass(dataclass, FairseqDataclass):
128
+ raise ValueError(
129
+ "Dataclass {} must extend FairseqDataclass".format(dataclass)
130
+ )
131
+
132
+ cls.__dataclass = dataclass
133
+ if dataclass is not None:
134
+ MODEL_DATACLASS_REGISTRY[name] = dataclass
135
+
136
+ cs = ConfigStore.instance()
137
+ node = dataclass()
138
+ node._name = name
139
+ cs.store(name=name, group="model", node=node, provider="fairseq")
140
+
141
+ @register_model_architecture(name, name)
142
+ def noop(_):
143
+ pass
144
+
145
+ return cls
146
+
147
+ return register_model_cls
148
+
149
+
150
+ def register_model_architecture(model_name, arch_name):
151
+ """
152
+ New model architectures can be added to fairseq with the
153
+ :func:`register_model_architecture` function decorator. After registration,
154
+ model architectures can be selected with the ``--arch`` command-line
155
+ argument.
156
+
157
+ For example::
158
+
159
+ @register_model_architecture('lstm', 'lstm_luong_wmt_en_de')
160
+ def lstm_luong_wmt_en_de(cfg):
161
+ args.encoder_embed_dim = getattr(cfg.model, 'encoder_embed_dim', 1000)
162
+ (...)
163
+
164
+ The decorated function should take a single argument *cfg*, which is a
165
+ :class:`omegaconf.DictConfig`. The decorated function should modify these
166
+ arguments in-place to match the desired architecture.
167
+
168
+ Args:
169
+ model_name (str): the name of the Model (Model must already be
170
+ registered)
171
+ arch_name (str): the name of the model architecture (``--arch``)
172
+ """
173
+
174
+ def register_model_arch_fn(fn):
175
+ if model_name not in MODEL_REGISTRY:
176
+ raise ValueError(
177
+ "Cannot register model architecture for unknown model type ({})".format(
178
+ model_name
179
+ )
180
+ )
181
+ if arch_name in ARCH_MODEL_REGISTRY:
182
+ raise ValueError(
183
+ "Cannot register duplicate model architecture ({})".format(arch_name)
184
+ )
185
+ if not callable(fn):
186
+ raise ValueError(
187
+ "Model architecture must be callable ({})".format(arch_name)
188
+ )
189
+ ARCH_MODEL_REGISTRY[arch_name] = MODEL_REGISTRY[model_name]
190
+ ARCH_MODEL_NAME_REGISTRY[arch_name] = model_name
191
+ ARCH_MODEL_INV_REGISTRY.setdefault(model_name, []).append(arch_name)
192
+ ARCH_CONFIG_REGISTRY[arch_name] = fn
193
+ return fn
194
+
195
+ return register_model_arch_fn
196
+
197
+
198
+ def import_models(models_dir, namespace):
199
+ for file in os.listdir(models_dir):
200
+ path = os.path.join(models_dir, file)
201
+ if (
202
+ not file.startswith("_")
203
+ and not file.startswith(".")
204
+ and (file.endswith(".py") or os.path.isdir(path))
205
+ ):
206
+ model_name = file[: file.find(".py")] if file.endswith(".py") else file
207
+ importlib.import_module(namespace + "." + model_name)
208
+
209
+ # extra `model_parser` for sphinx
210
+ if model_name in MODEL_REGISTRY:
211
+ parser = argparse.ArgumentParser(add_help=False)
212
+ group_archs = parser.add_argument_group("Named architectures")
213
+ group_archs.add_argument(
214
+ "--arch", choices=ARCH_MODEL_INV_REGISTRY[model_name]
215
+ )
216
+ group_args = parser.add_argument_group(
217
+ "Additional command-line arguments"
218
+ )
219
+ MODEL_REGISTRY[model_name].add_args(group_args)
220
+ globals()[model_name + "_parser"] = parser
221
+
222
+
223
+ # automatically import any Python files in the models/ directory
224
+ models_dir = os.path.dirname(__file__)
225
+ import_models(models_dir, "fairseq.models")
avh-align_core/fairseq/models/bart/__init__.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ from .hub_interface import * # noqa
7
+ from .model import * # noqa
avh-align_core/fairseq/models/bart/hub_interface.py ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import copy
7
+ import logging
8
+ from typing import Dict, List
9
+
10
+ import numpy as np
11
+ import torch
12
+ import torch.nn as nn
13
+ import torch.nn.functional as F
14
+ from fairseq import utils
15
+ from fairseq.data import encoders
16
+ from fairseq.hub_utils import GeneratorHubInterface
17
+ from omegaconf import open_dict
18
+
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class BARTHubInterface(GeneratorHubInterface):
24
+ """A simple PyTorch Hub interface to BART.
25
+
26
+ Usage: https://github.com/pytorch/fairseq/tree/master/examples/bart
27
+ """
28
+
29
+ def __init__(self, cfg, task, model):
30
+ super().__init__(cfg, task, [model])
31
+ self.model = self.models[0]
32
+
33
+ def encode(
34
+ self, sentence: str, *addl_sentences, no_separator=True
35
+ ) -> torch.LongTensor:
36
+ """
37
+ BPE-encode a sentence (or multiple sentences).
38
+
39
+ Every sequence begins with a beginning-of-sentence (`<s>`) symbol.
40
+ Every sentence ends with an end-of-sentence (`</s>`).
41
+
42
+ Example (single sentence): `<s> a b c </s>`
43
+ Example (sentence pair): `<s> d e f </s> 1 2 3 </s>`
44
+
45
+ The BPE encoding follows GPT-2. One subtle detail is that the GPT-2 BPE
46
+ requires leading spaces. For example::
47
+
48
+ >>> bart.encode('Hello world').tolist()
49
+ [0, 31414, 232, 2]
50
+ >>> bart.encode(' world').tolist()
51
+ [0, 232, 2]
52
+ >>> bart.encode('world').tolist()
53
+ [0, 8331, 2]
54
+ """
55
+ tokens = self.bpe.encode(sentence)
56
+ if len(tokens.split(" ")) > min(self.max_positions) - 2:
57
+ tokens = " ".join(tokens.split(" ")[: min(self.max_positions) - 2])
58
+ bpe_sentence = "<s> " + tokens + " </s>"
59
+ for s in addl_sentences:
60
+ bpe_sentence += " </s>" if not no_separator else ""
61
+ bpe_sentence += " " + self.bpe.encode(s) + " </s>"
62
+ tokens = self.task.source_dictionary.encode_line(bpe_sentence, append_eos=False)
63
+ return tokens.long()
64
+
65
+ def decode(self, tokens: torch.LongTensor):
66
+ assert tokens.dim() == 1
67
+ tokens = tokens.cpu().numpy()
68
+ if tokens[0] == self.task.source_dictionary.bos():
69
+ tokens = tokens[1:] # remove <s>
70
+ eos_mask = tokens == self.task.source_dictionary.eos()
71
+ doc_mask = eos_mask[1:] & eos_mask[:-1]
72
+ sentences = np.split(tokens, doc_mask.nonzero()[0] + 1)
73
+ sentences = [
74
+ self.bpe.decode(self.task.source_dictionary.string(s)) for s in sentences
75
+ ]
76
+ if len(sentences) == 1:
77
+ return sentences[0]
78
+ return sentences
79
+
80
+ def _build_sample(self, src_tokens: List[torch.LongTensor]):
81
+ # assert torch.is_tensor(src_tokens)
82
+ dataset = self.task.build_dataset_for_inference(
83
+ src_tokens,
84
+ [x.numel() for x in src_tokens],
85
+ )
86
+ sample = dataset.collater(dataset)
87
+ sample = utils.apply_to_sample(lambda tensor: tensor.to(self.device), sample)
88
+ return sample
89
+
90
+ def generate(
91
+ self,
92
+ tokenized_sentences: List[torch.LongTensor],
93
+ *args,
94
+ inference_step_args=None,
95
+ skip_invalid_size_inputs=False,
96
+ **kwargs
97
+ ) -> List[List[Dict[str, torch.Tensor]]]:
98
+ inference_step_args = inference_step_args or {}
99
+ if "prefix_tokens" in inference_step_args:
100
+ raise NotImplementedError("prefix generation not implemented for BART")
101
+ res = []
102
+ for batch in self._build_batches(tokenized_sentences, skip_invalid_size_inputs):
103
+ src_tokens = batch['net_input']['src_tokens']
104
+ inference_step_args["prefix_tokens"] =src_tokens.new_full(
105
+ (src_tokens.size(0), 1), fill_value=self.task.source_dictionary.bos()
106
+ ).to(device=self.device)
107
+ results = super().generate(
108
+ src_tokens,
109
+ *args,
110
+ inference_step_args=inference_step_args,
111
+ skip_invalid_size_inputs=skip_invalid_size_inputs,
112
+ **kwargs
113
+ )
114
+ for id, hypos in zip(batch['id'].tolist(), results):
115
+ res.append((id, hypos))
116
+ res = [hypos for _, hypos in sorted(res, key=lambda x: x[0])]
117
+ return res
118
+
119
+ def extract_features(
120
+ self, tokens: torch.LongTensor, return_all_hiddens: bool = False
121
+ ) -> torch.Tensor:
122
+ if tokens.dim() == 1:
123
+ tokens = tokens.unsqueeze(0)
124
+ if tokens.size(-1) > min(self.model.max_positions()):
125
+ raise ValueError(
126
+ "tokens exceeds maximum length: {} > {}".format(
127
+ tokens.size(-1), self.model.max_positions()
128
+ )
129
+ )
130
+ tokens.to(device=self.device),
131
+ prev_output_tokens = tokens.clone()
132
+
133
+ prev_output_tokens[:, 0] = tokens.gather(
134
+ 1,
135
+ (tokens.ne(self.task.source_dictionary.pad()).sum(dim=1) - 1).unsqueeze(-1),
136
+ ).squeeze()
137
+
138
+ prev_output_tokens[:, 1:] = tokens[:, :-1]
139
+ features, extra = self.model(
140
+ src_tokens=tokens,
141
+ src_lengths=None,
142
+ prev_output_tokens=prev_output_tokens,
143
+ features_only=True,
144
+ return_all_hiddens=return_all_hiddens,
145
+ )
146
+ if return_all_hiddens:
147
+ # convert from T x B x C -> B x T x C
148
+ inner_states = extra["inner_states"]
149
+ return [inner_state.transpose(0, 1) for inner_state in inner_states]
150
+ else:
151
+ return features # just the last layer's features
152
+
153
+ def register_classification_head(
154
+ self, name: str, num_classes: int = None, embedding_size: int = None, **kwargs
155
+ ):
156
+ self.model.register_classification_head(
157
+ name, num_classes=num_classes, embedding_size=embedding_size, **kwargs
158
+ )
159
+
160
+ def predict(self, head: str, tokens: torch.LongTensor, return_logits: bool = False):
161
+ if tokens.dim() == 1:
162
+ tokens = tokens.unsqueeze(0)
163
+ features = self.extract_features(tokens.to(device=self.device))
164
+ sentence_representation = features[
165
+ tokens.eq(self.task.source_dictionary.eos()), :
166
+ ].view(features.size(0), -1, features.size(-1))[:, -1, :]
167
+
168
+ logits = self.model.classification_heads[head](sentence_representation)
169
+ if return_logits:
170
+ return logits
171
+ return F.log_softmax(logits, dim=-1)
172
+
173
+ def fill_mask(
174
+ self,
175
+ masked_inputs: List[str],
176
+ topk: int = 5,
177
+ match_source_len: bool = True,
178
+ **generate_kwargs
179
+ ):
180
+ masked_token = '<mask>'
181
+ batch_tokens = []
182
+ for masked_input in masked_inputs:
183
+ assert masked_token in masked_input, \
184
+ "please add one {} token for the input".format(masked_token)
185
+
186
+ text_spans = masked_input.split(masked_token)
187
+ text_spans_bpe = (' {0} '.format(masked_token)).join(
188
+ [self.bpe.encode(text_span.rstrip()) for text_span in text_spans]
189
+ ).strip()
190
+ tokens = self.task.source_dictionary.encode_line(
191
+ '<s> ' + text_spans_bpe + ' </s>',
192
+ append_eos=False,
193
+ add_if_not_exist=False,
194
+ ).long()
195
+ batch_tokens.append(tokens)
196
+
197
+ # ensure beam size is at least as big as topk
198
+ generate_kwargs['beam'] = max(
199
+ topk,
200
+ generate_kwargs.get('beam', -1),
201
+ )
202
+ generate_kwargs['match_source_len'] = match_source_len
203
+ batch_hypos = self.generate(batch_tokens, **generate_kwargs)
204
+
205
+ return [
206
+ [(self.decode(hypo['tokens']), hypo['score']) for hypo in hypos[:topk]]
207
+ for hypos in batch_hypos
208
+ ]
avh-align_core/fairseq/models/bart/model.py ADDED
@@ -0,0 +1,384 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+ """
6
+ BART: Denoising Sequence-to-Sequence Pre-training for
7
+ Natural Language Generation, Translation, and Comprehension
8
+ """
9
+ from typing import Optional
10
+
11
+ import logging
12
+
13
+ import torch
14
+ import torch.nn as nn
15
+ from fairseq import utils
16
+ from fairseq.models import register_model, register_model_architecture
17
+ from fairseq.models.transformer import TransformerModel
18
+ from fairseq.modules.transformer_sentence_encoder import init_bert_params
19
+
20
+ from .hub_interface import BARTHubInterface
21
+
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ @register_model("bart")
27
+ class BARTModel(TransformerModel):
28
+ __jit_unused_properties__ = ["supported_targets"]
29
+
30
+ @classmethod
31
+ def hub_models(cls):
32
+ return {
33
+ "bart.base": "http://dl.fbaipublicfiles.com/fairseq/models/bart.base.tar.gz",
34
+ "bart.large": "http://dl.fbaipublicfiles.com/fairseq/models/bart.large.tar.gz",
35
+ "bart.large.mnli": "http://dl.fbaipublicfiles.com/fairseq/models/bart.large.mnli.tar.gz",
36
+ "bart.large.cnn": "http://dl.fbaipublicfiles.com/fairseq/models/bart.large.cnn.tar.gz",
37
+ "bart.large.xsum": "http://dl.fbaipublicfiles.com/fairseq/models/bart.large.xsum.tar.gz",
38
+ }
39
+
40
+ def __init__(self, args, encoder, decoder):
41
+ super().__init__(args, encoder, decoder)
42
+
43
+ # We follow BERT's random weight initialization
44
+ self.apply(init_bert_params)
45
+
46
+ self.classification_heads = nn.ModuleDict()
47
+ if hasattr(self.encoder, "dictionary"):
48
+ self.eos: int = self.encoder.dictionary.eos()
49
+
50
+ @staticmethod
51
+ def add_args(parser):
52
+ super(BARTModel, BARTModel).add_args(parser)
53
+ parser.add_argument(
54
+ "--pooler-dropout",
55
+ type=float,
56
+ metavar="D",
57
+ help="dropout probability in the masked_lm pooler layers",
58
+ )
59
+ parser.add_argument(
60
+ "--pooler-activation-fn",
61
+ choices=utils.get_available_activation_fns(),
62
+ help="activation function to use for pooler layer",
63
+ )
64
+ parser.add_argument(
65
+ "--spectral-norm-classification-head",
66
+ action="store_true",
67
+ help="Apply spectral normalization on the classification head",
68
+ )
69
+
70
+ @property
71
+ def supported_targets(self):
72
+ return {"self"}
73
+
74
+ def forward(
75
+ self,
76
+ src_tokens,
77
+ src_lengths,
78
+ prev_output_tokens,
79
+ features_only: bool = False,
80
+ classification_head_name: Optional[str] = None,
81
+ token_embeddings: Optional[torch.Tensor] = None,
82
+ return_all_hiddens: bool = True,
83
+ alignment_layer: Optional[int] = None,
84
+ alignment_heads: Optional[int] = None,
85
+ ):
86
+ if classification_head_name is not None:
87
+ features_only = True
88
+
89
+ encoder_out = self.encoder(
90
+ src_tokens,
91
+ src_lengths=src_lengths,
92
+ token_embeddings=token_embeddings,
93
+ return_all_hiddens=return_all_hiddens
94
+ )
95
+ x, extra = self.decoder(
96
+ prev_output_tokens,
97
+ encoder_out=encoder_out,
98
+ features_only=features_only,
99
+ alignment_layer=alignment_layer,
100
+ alignment_heads=alignment_heads,
101
+ src_lengths=src_lengths,
102
+ return_all_hiddens=return_all_hiddens,
103
+ )
104
+ eos: int = self.eos
105
+ if classification_head_name is not None:
106
+ sentence_representation = x[
107
+ src_tokens.eq(eos), :
108
+ ].view(x.size(0), -1, x.size(-1))[:, -1, :]
109
+ for k, head in self.classification_heads.items():
110
+ # for torch script only supports iteration
111
+ if k == classification_head_name:
112
+ x = head(sentence_representation)
113
+ break
114
+ return x, extra
115
+
116
+ @classmethod
117
+ def from_pretrained(
118
+ cls,
119
+ model_name_or_path,
120
+ checkpoint_file="model.pt",
121
+ data_name_or_path=".",
122
+ bpe="gpt2",
123
+ sample_break_mode="eos",
124
+ **kwargs,
125
+ ):
126
+ from fairseq import hub_utils
127
+
128
+ x = hub_utils.from_pretrained(
129
+ model_name_or_path,
130
+ checkpoint_file,
131
+ data_name_or_path,
132
+ archive_map=cls.hub_models(),
133
+ bpe=bpe,
134
+ load_checkpoint_heads=True,
135
+ sample_break_mode=sample_break_mode,
136
+ **kwargs,
137
+ )
138
+ return BARTHubInterface(x["args"], x["task"], x["models"][0])
139
+
140
+ def register_classification_head(
141
+ self, name, num_classes=None, inner_dim=None, **kwargs
142
+ ):
143
+ """Register a classification head."""
144
+ logger.info("Registering classification head: {0}".format(name))
145
+ if name in self.classification_heads:
146
+ prev_num_classes = self.classification_heads[name].out_proj.out_features
147
+ prev_inner_dim = self.classification_heads[name].dense.out_features
148
+ if num_classes != prev_num_classes or inner_dim != prev_inner_dim:
149
+ logger.warning(
150
+ 're-registering head "{}" with num_classes {} (prev: {}) '
151
+ "and inner_dim {} (prev: {})".format(
152
+ name, num_classes, prev_num_classes, inner_dim, prev_inner_dim
153
+ )
154
+ )
155
+ self.classification_heads[name] = BARTClassificationHead(
156
+ input_dim=self.args.encoder_embed_dim,
157
+ inner_dim=inner_dim or self.args.encoder_embed_dim,
158
+ num_classes=num_classes,
159
+ activation_fn=self.args.pooler_activation_fn,
160
+ pooler_dropout=self.args.pooler_dropout,
161
+ do_spectral_norm=getattr(
162
+ self.args, "spectral_norm_classification_head", False
163
+ ),
164
+ )
165
+
166
+ def upgrade_state_dict_named(self, state_dict, name):
167
+ super().upgrade_state_dict_named(state_dict, name)
168
+
169
+ prefix = name + "." if name != "" else ""
170
+ current_head_names = (
171
+ []
172
+ if not hasattr(self, "classification_heads")
173
+ else self.classification_heads.keys()
174
+ )
175
+
176
+ # Handle new classification heads present in the state dict.
177
+ keys_to_delete = []
178
+ for k in state_dict.keys():
179
+ if not k.startswith(prefix + "classification_heads."):
180
+ continue
181
+
182
+ head_name = k[len(prefix + "classification_heads.") :].split(".")[0]
183
+ num_classes = state_dict[
184
+ prefix + "classification_heads." + head_name + ".out_proj.weight"
185
+ ].size(0)
186
+ inner_dim = state_dict[
187
+ prefix + "classification_heads." + head_name + ".dense.weight"
188
+ ].size(0)
189
+
190
+ if getattr(self.args, "load_checkpoint_heads", False):
191
+ if head_name not in current_head_names:
192
+ self.register_classification_head(head_name, num_classes, inner_dim)
193
+ else:
194
+ if head_name not in current_head_names:
195
+ logger.warning(
196
+ "deleting classification head ({}) from checkpoint "
197
+ "not present in current model: {}".format(head_name, k)
198
+ )
199
+ keys_to_delete.append(k)
200
+ elif (
201
+ num_classes
202
+ != self.classification_heads[head_name].out_proj.out_features
203
+ or inner_dim
204
+ != self.classification_heads[head_name].dense.out_features
205
+ ):
206
+ logger.warning(
207
+ "deleting classification head ({}) from checkpoint "
208
+ "with different dimensions than current model: {}".format(
209
+ head_name, k
210
+ )
211
+ )
212
+ keys_to_delete.append(k)
213
+ for k in keys_to_delete:
214
+ del state_dict[k]
215
+
216
+ def truncate_emb(key):
217
+ if key in state_dict:
218
+ state_dict[key] = state_dict[key][:-1, :]
219
+
220
+ # When finetuning on translation task, remove last row of
221
+ # embedding matrix that corresponds to mask_idx token.
222
+ loaded_dict_size = state_dict["encoder.embed_tokens.weight"].size(0)
223
+ if (
224
+ loaded_dict_size == len(self.encoder.dictionary) + 1
225
+ and "<mask>" not in self.encoder.dictionary
226
+ ):
227
+ truncate_emb("encoder.embed_tokens.weight")
228
+ truncate_emb("decoder.embed_tokens.weight")
229
+ truncate_emb("encoder.output_projection.weight")
230
+ truncate_emb("decoder.output_projection.weight")
231
+
232
+ # When continued pretraining on new set of languages for mbart,
233
+ # add extra lang embeddings at the end of embed_tokens.
234
+ # Note: newly added languages are assumed to have been added at the end.
235
+ if self.args.task == "multilingual_denoising" and loaded_dict_size < len(
236
+ self.encoder.dictionary
237
+ ):
238
+ logger.info(
239
+ "Adding extra language embeddings not found in pretrained model for "
240
+ "continued pretraining of MBART on new set of languages."
241
+ )
242
+ loaded_mask_token_embedding = state_dict["encoder.embed_tokens.weight"][
243
+ -1, :
244
+ ]
245
+
246
+ num_langids_to_add = len(self.encoder.dictionary) - loaded_dict_size
247
+ embed_dim = state_dict["encoder.embed_tokens.weight"].size(1)
248
+
249
+ new_lang_embed_to_add = torch.zeros(num_langids_to_add, embed_dim)
250
+ nn.init.normal_(new_lang_embed_to_add, mean=0, std=embed_dim ** -0.5)
251
+ new_lang_embed_to_add = new_lang_embed_to_add.to(
252
+ dtype=state_dict["encoder.embed_tokens.weight"].dtype,
253
+ )
254
+
255
+ state_dict["encoder.embed_tokens.weight"] = torch.cat(
256
+ [
257
+ state_dict["encoder.embed_tokens.weight"][
258
+ : loaded_dict_size - 1, :
259
+ ],
260
+ new_lang_embed_to_add,
261
+ loaded_mask_token_embedding.unsqueeze(0),
262
+ ]
263
+ )
264
+ state_dict["decoder.embed_tokens.weight"] = torch.cat(
265
+ [
266
+ state_dict["decoder.embed_tokens.weight"][
267
+ : loaded_dict_size - 1, :
268
+ ],
269
+ new_lang_embed_to_add,
270
+ loaded_mask_token_embedding.unsqueeze(0),
271
+ ]
272
+ )
273
+
274
+ # Copy any newly-added classification heads into the state dict
275
+ # with their current weights.
276
+ if hasattr(self, "classification_heads"):
277
+ cur_state = self.classification_heads.state_dict()
278
+ for k, v in cur_state.items():
279
+ if prefix + "classification_heads." + k not in state_dict:
280
+ logger.info("Overwriting " + prefix + "classification_heads." + k)
281
+ state_dict[prefix + "classification_heads." + k] = v
282
+
283
+
284
+ class BARTClassificationHead(nn.Module):
285
+ """Head for sentence-level classification tasks."""
286
+
287
+ def __init__(
288
+ self,
289
+ input_dim,
290
+ inner_dim,
291
+ num_classes,
292
+ activation_fn,
293
+ pooler_dropout,
294
+ do_spectral_norm=False,
295
+ ):
296
+ super().__init__()
297
+ self.dense = nn.Linear(input_dim, inner_dim)
298
+ self.activation_fn = utils.get_activation_fn(activation_fn)
299
+ self.dropout = nn.Dropout(p=pooler_dropout)
300
+ self.out_proj = nn.Linear(inner_dim, num_classes)
301
+
302
+ if do_spectral_norm:
303
+ self.out_proj = torch.nn.utils.spectral_norm(self.out_proj)
304
+
305
+ def forward(self, features, **kwargs):
306
+ x = features
307
+ x = self.dropout(x)
308
+ x = self.dense(x)
309
+ x = self.activation_fn(x)
310
+ x = self.dropout(x)
311
+ x = self.out_proj(x)
312
+ return x
313
+
314
+
315
+ @register_model_architecture("bart", "bart_large")
316
+ def bart_large_architecture(args):
317
+ args.encoder_embed_path = getattr(args, "encoder_embed_path", None)
318
+ args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024)
319
+ args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 4 * 1024)
320
+ args.encoder_layers = getattr(args, "encoder_layers", 12)
321
+ args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 16)
322
+ args.encoder_normalize_before = getattr(args, "encoder_normalize_before", False)
323
+ args.encoder_learned_pos = getattr(args, "encoder_learned_pos", True)
324
+ args.decoder_embed_path = getattr(args, "decoder_embed_path", None)
325
+ args.decoder_embed_dim = getattr(args, "decoder_embed_dim", args.encoder_embed_dim)
326
+ args.decoder_ffn_embed_dim = getattr(
327
+ args, "decoder_ffn_embed_dim", args.encoder_ffn_embed_dim
328
+ )
329
+ args.decoder_layers = getattr(args, "decoder_layers", 12)
330
+ args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16)
331
+ args.decoder_normalize_before = getattr(args, "decoder_normalize_before", False)
332
+ args.decoder_learned_pos = getattr(args, "decoder_learned_pos", True)
333
+ args.attention_dropout = getattr(args, "attention_dropout", 0.0)
334
+ args.relu_dropout = getattr(args, "relu_dropout", 0.0)
335
+ args.dropout = getattr(args, "dropout", 0.1)
336
+ args.max_target_positions = getattr(args, "max_target_positions", 1024)
337
+ args.max_source_positions = getattr(args, "max_source_positions", 1024)
338
+ args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None)
339
+ args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0)
340
+ args.share_decoder_input_output_embed = getattr(
341
+ args, "share_decoder_input_output_embed", True
342
+ )
343
+ args.share_all_embeddings = getattr(args, "share_all_embeddings", True)
344
+
345
+ args.decoder_output_dim = getattr(
346
+ args, "decoder_output_dim", args.decoder_embed_dim
347
+ )
348
+ args.decoder_input_dim = getattr(args, "decoder_input_dim", args.decoder_embed_dim)
349
+
350
+ args.no_scale_embedding = getattr(args, "no_scale_embedding", True)
351
+ args.layernorm_embedding = getattr(args, "layernorm_embedding", True)
352
+
353
+ args.activation_fn = getattr(args, "activation_fn", "gelu")
354
+ args.pooler_activation_fn = getattr(args, "pooler_activation_fn", "tanh")
355
+ args.pooler_dropout = getattr(args, "pooler_dropout", 0.0)
356
+
357
+
358
+ @register_model_architecture("bart", "bart_base")
359
+ def bart_base_architecture(args):
360
+ args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 768)
361
+ args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 4 * 768)
362
+ args.encoder_layers = getattr(args, "encoder_layers", 6)
363
+ args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 12)
364
+ args.decoder_layers = getattr(args, "decoder_layers", 6)
365
+ args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 12)
366
+ bart_large_architecture(args)
367
+
368
+
369
+ @register_model_architecture("bart", "mbart_large")
370
+ def mbart_large_architecture(args):
371
+ args.no_scale_embedding = getattr(args, "no_scale_embedding", False)
372
+ bart_large_architecture(args)
373
+
374
+
375
+ @register_model_architecture("bart", "mbart_base")
376
+ def mbart_base_architecture(args):
377
+ args.no_scale_embedding = getattr(args, "no_scale_embedding", False)
378
+ bart_base_architecture(args)
379
+
380
+
381
+ @register_model_architecture("bart", "mbart_base_wmt20")
382
+ def mbart_base_wmt20_architecture(args):
383
+ args.layernorm_embedding = getattr(args, "layernorm_embedding", False)
384
+ mbart_base_architecture(args)
avh-align_core/fairseq/models/composite_encoder.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ from .fairseq_encoder import FairseqEncoder
7
+
8
+
9
+ class CompositeEncoder(FairseqEncoder):
10
+ """
11
+ A wrapper around a dictionary of :class:`FairseqEncoder` objects.
12
+
13
+ We run forward on each encoder and return a dictionary of outputs. The first
14
+ encoder's dictionary is used for initialization.
15
+
16
+ Args:
17
+ encoders (dict): a dictionary of :class:`FairseqEncoder` objects.
18
+ """
19
+
20
+ def __init__(self, encoders):
21
+ super().__init__(next(iter(encoders.values())).dictionary)
22
+ self.encoders = encoders
23
+ for key in self.encoders:
24
+ self.add_module(key, self.encoders[key])
25
+
26
+ def forward(self, src_tokens, src_lengths):
27
+ """
28
+ Args:
29
+ src_tokens (LongTensor): tokens in the source language of shape
30
+ `(batch, src_len)`
31
+ src_lengths (LongTensor): lengths of each source sentence of shape
32
+ `(batch)`
33
+
34
+ Returns:
35
+ dict:
36
+ the outputs from each Encoder
37
+ """
38
+ encoder_out = {}
39
+ for key in self.encoders:
40
+ encoder_out[key] = self.encoders[key](src_tokens, src_lengths)
41
+ return encoder_out
42
+
43
+ def reorder_encoder_out(self, encoder_out, new_order):
44
+ """Reorder encoder output according to new_order."""
45
+ for key in self.encoders:
46
+ encoder_out[key] = self.encoders[key].reorder_encoder_out(
47
+ encoder_out[key], new_order
48
+ )
49
+ return encoder_out
50
+
51
+ def max_positions(self):
52
+ return min(self.encoders[key].max_positions() for key in self.encoders)
53
+
54
+ def upgrade_state_dict(self, state_dict):
55
+ for key in self.encoders:
56
+ self.encoders[key].upgrade_state_dict(state_dict)
57
+ return state_dict
avh-align_core/fairseq/models/distributed_fairseq_model.py ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import logging
7
+ import os
8
+ import signal
9
+ import threading
10
+
11
+ import torch
12
+ import torch.nn as nn
13
+ from torch.nn.parallel import DistributedDataParallel
14
+
15
+ from fairseq.distributed import (
16
+ DistributedTimeoutWrapper,
17
+ LegacyDistributedDataParallel,
18
+ ModuleProxyWrapper,
19
+ TPUDistributedDataParallel,
20
+ )
21
+
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ _GOSSIP_DISABLED = False
27
+ try:
28
+ import gossip
29
+ except ImportError:
30
+ _GOSSIP_DISABLED = True
31
+
32
+
33
+ def DistributedFairseqModel(args, model, process_group, device):
34
+ """
35
+ Wrap a *model* to support distributed data parallel training.
36
+
37
+ This is similar to the built-in DistributedDataParallel, but allows
38
+ additional configuration of the DistributedDataParallel class to
39
+ use, and also provides easier access to the wrapped model by
40
+ forwarding requests for missing attributes to the wrapped model.
41
+
42
+ Args:
43
+ args (argparse.Namespace): fairseq args
44
+ model (BaseFairseqModel): model to wrap
45
+ process_group: the c10d process group to be used for distributed data
46
+ parallel all-reduction.
47
+ device: device to move model to
48
+ """
49
+ assert isinstance(model, nn.Module)
50
+ if args.tpu:
51
+ wrapped_model = TPUDistributedDataParallel(
52
+ module=model.to(device),
53
+ process_group=process_group,
54
+ )
55
+ # forward missing getattr and state_dict/load_state_dict to orig model
56
+ wrapped_model = ModuleProxyWrapper(wrapped_model)
57
+ elif args.ddp_backend in {"c10d", "pytorch_ddp"}:
58
+ wrapped_model = DistributedDataParallel(
59
+ module=model.to(device),
60
+ device_ids=[args.device_id],
61
+ output_device=args.device_id,
62
+ broadcast_buffers=args.broadcast_buffers,
63
+ bucket_cap_mb=args.bucket_cap_mb,
64
+ process_group=process_group,
65
+ find_unused_parameters=args.find_unused_parameters,
66
+ )
67
+ if args.ddp_comm_hook == "fp16":
68
+ logger.info("enable fp16 communication hook in DDP")
69
+ try:
70
+ from torch.distributed.algorithms.ddp_comm_hooks import (
71
+ register_ddp_comm_hook,
72
+ DDPCommHookType,
73
+ )
74
+ except:
75
+ logger.error(
76
+ "Could not import from torch.distributed.algorithms.ddp_comm_hooks; you may need to update your pytorch version"
77
+ )
78
+ raise
79
+
80
+ register_ddp_comm_hook(DDPCommHookType.FP16_COMPRESS, wrapped_model)
81
+ # forward missing getattr and state_dict/load_state_dict to orig model
82
+ wrapped_model = ModuleProxyWrapper(wrapped_model)
83
+ elif args.ddp_backend in {"no_c10d", "legacy_ddp"}:
84
+ wrapped_model = LegacyDistributedDataParallel(
85
+ module=model.to(device),
86
+ buffer_size=2 ** 28,
87
+ process_group=process_group,
88
+ )
89
+ # forward missing getattr and state_dict/load_state_dict to orig model
90
+ wrapped_model = ModuleProxyWrapper(wrapped_model)
91
+ elif args.ddp_backend == "slow_mo":
92
+ if _GOSSIP_DISABLED:
93
+ raise ImportError(
94
+ "Cannot find gossip library. Please install from: "
95
+ "github.com/facebookresearch/stochastic_gradient_push"
96
+ )
97
+
98
+ # The values of slowmo_momentum below were obtained by tuning on the
99
+ # En-De 16 dataset by training the transformer_wmt_en_de_large model
100
+ if args.slowmo_momentum is None:
101
+ if args.distributed_world_size <= 16:
102
+ args.slowmo_momentum = 0.0
103
+ elif args.distributed_world_size <= 32:
104
+ args.slowmo_momentum = 0.2
105
+ elif args.distributed_world_size <= 64:
106
+ args.slowmo_momentum = 0.5
107
+ else:
108
+ args.slowmo_momentum = 0.6
109
+
110
+ wrapped_model = gossip.GossipDataParallel(
111
+ module=model.to(device),
112
+ device_ids=[args.device_id],
113
+ output_device=args.device_id,
114
+ broadcast_buffers=args.broadcast_buffers,
115
+ nprocs_per_node=args.nprocs_per_node,
116
+ slowmo_momentum=args.slowmo_momentum,
117
+ localsgd=(args.slowmo_algorithm == "LocalSGD"),
118
+ localsgd_frequency=args.localsgd_frequency,
119
+ )
120
+ # forward missing getattr and state_dict/load_state_dict to orig model
121
+ wrapped_model = ModuleProxyWrapper(wrapped_model)
122
+ elif args.ddp_backend == "fully_sharded":
123
+ try:
124
+ from fairscale.nn.data_parallel import FullyShardedDataParallel as FSDP
125
+ except ImportError:
126
+ raise ImportError(
127
+ "Cannot find FullyShardedDataParallel. "
128
+ "Please install fairscale with: pip install fairscale"
129
+ )
130
+ assert isinstance(model, FSDP), "expected model to already be wrapped in FSDP"
131
+ wrapped_model = model
132
+ if args.memory_efficient_fp16:
133
+ wrapped_model = wrapped_model.half()
134
+ if not args.cpu_offload:
135
+ wrapped_model = wrapped_model.to(device=device)
136
+ else:
137
+ raise ValueError("Unknown --ddp-backend: " + args.ddp_backend)
138
+
139
+ # kill hung distributed jobs after a timeout
140
+ if getattr(args, "heartbeat_timeout", -1) > 0:
141
+ wrapped_model = DistributedTimeoutWrapper(
142
+ wrapped_model, timeout=getattr(args, "heartbeat_timeout", -1)
143
+ )
144
+
145
+ return wrapped_model
avh-align_core/fairseq/models/fairseq_decoder.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ from typing import Dict, List, Optional, Tuple
7
+
8
+ import torch.nn as nn
9
+ from fairseq import utils
10
+ from torch import Tensor
11
+
12
+
13
+ class FairseqDecoder(nn.Module):
14
+ """Base class for decoders."""
15
+
16
+ def __init__(self, dictionary):
17
+ super().__init__()
18
+ self.dictionary = dictionary
19
+ self.onnx_trace = False
20
+ self.adaptive_softmax = None
21
+
22
+
23
+ def forward(self, prev_output_tokens, encoder_out=None, **kwargs):
24
+ """
25
+ Args:
26
+ prev_output_tokens (LongTensor): shifted output tokens of shape
27
+ `(batch, tgt_len)`, for teacher forcing
28
+ encoder_out (dict, optional): output from the encoder, used for
29
+ encoder-side attention
30
+
31
+ Returns:
32
+ tuple:
33
+ - the decoder's output of shape `(batch, tgt_len, vocab)`
34
+ - a dictionary with any model-specific outputs
35
+ """
36
+ x, extra = self.extract_features(
37
+ prev_output_tokens, encoder_out=encoder_out, **kwargs
38
+ )
39
+ x = self.output_layer(x)
40
+ return x, extra
41
+
42
+ def extract_features(self, prev_output_tokens, encoder_out=None, **kwargs):
43
+ """
44
+ Returns:
45
+ tuple:
46
+ - the decoder's features of shape `(batch, tgt_len, embed_dim)`
47
+ - a dictionary with any model-specific outputs
48
+ """
49
+ raise NotImplementedError
50
+
51
+ def output_layer(self, features, **kwargs):
52
+ """
53
+ Project features to the default output size, e.g., vocabulary size.
54
+
55
+ Args:
56
+ features (Tensor): features returned by *extract_features*.
57
+ """
58
+ raise NotImplementedError
59
+
60
+ def get_normalized_probs(
61
+ self,
62
+ net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]],
63
+ log_probs: bool,
64
+ sample: Optional[Dict[str, Tensor]] = None,
65
+ ):
66
+ """Get normalized probabilities (or log probs) from a net's output."""
67
+ return self.get_normalized_probs_scriptable(net_output, log_probs, sample)
68
+
69
+ # TorchScript doesn't support super() method so that the scriptable Subclass
70
+ # can't access the base class model in Torchscript.
71
+ # Current workaround is to add a helper function with different name and
72
+ # call the helper function from scriptable Subclass.
73
+ def get_normalized_probs_scriptable(
74
+ self,
75
+ net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]],
76
+ log_probs: bool,
77
+ sample: Optional[Dict[str, Tensor]] = None,
78
+ ):
79
+ """Get normalized probabilities (or log probs) from a net's output."""
80
+
81
+ if hasattr(self, "adaptive_softmax") and self.adaptive_softmax is not None:
82
+ if sample is not None:
83
+ assert "target" in sample
84
+ target = sample["target"]
85
+ else:
86
+ target = None
87
+ out = self.adaptive_softmax.get_log_prob(net_output[0], target=target)
88
+ return out.exp_() if not log_probs else out
89
+
90
+ logits = net_output[0]
91
+ if log_probs:
92
+ return utils.log_softmax(logits, dim=-1, onnx_trace=self.onnx_trace)
93
+ else:
94
+ return utils.softmax(logits, dim=-1, onnx_trace=self.onnx_trace)
95
+
96
+ def max_positions(self):
97
+ """Maximum input length supported by the decoder."""
98
+ return 1e6 # an arbitrary large number
99
+
100
+ def upgrade_state_dict_named(self, state_dict, name):
101
+ """Upgrade old state dicts to work with newer code."""
102
+ return state_dict
103
+
104
+ def prepare_for_onnx_export_(self):
105
+ self.onnx_trace = True
avh-align_core/fairseq/models/fairseq_encoder.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ from typing import Dict, List, NamedTuple, Optional
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+ from torch import Tensor
11
+
12
+
13
+ EncoderOut = NamedTuple(
14
+ "EncoderOut",
15
+ [
16
+ ("encoder_out", Tensor), # T x B x C
17
+ ("encoder_padding_mask", Optional[Tensor]), # B x T
18
+ ("encoder_embedding", Optional[Tensor]), # B x T x C
19
+ ("encoder_states", Optional[List[Tensor]]), # List[T x B x C]
20
+ ("src_tokens", Optional[Tensor]), # B x T
21
+ ("src_lengths", Optional[Tensor]), # B x 1
22
+ ],
23
+ )
24
+
25
+
26
+ class FairseqEncoder(nn.Module):
27
+ """Base class for encoders."""
28
+
29
+ def __init__(self, dictionary):
30
+ super().__init__()
31
+ self.dictionary = dictionary
32
+
33
+ def forward(self, src_tokens, src_lengths=None, **kwargs):
34
+ """
35
+ Args:
36
+ src_tokens (LongTensor): tokens in the source language of shape
37
+ `(batch, src_len)`
38
+ src_lengths (LongTensor): lengths of each source sentence of shape
39
+ `(batch)`
40
+ """
41
+ raise NotImplementedError
42
+
43
+ def forward_torchscript(self, net_input: Dict[str, Tensor]):
44
+ """A TorchScript-compatible version of forward.
45
+
46
+ Encoders which use additional arguments may want to override
47
+ this method for TorchScript compatibility.
48
+ """
49
+ if torch.jit.is_scripting():
50
+ return self.forward(
51
+ src_tokens=net_input["src_tokens"],
52
+ src_lengths=net_input["src_lengths"],
53
+ )
54
+ else:
55
+ return self.forward_non_torchscript(net_input)
56
+
57
+ @torch.jit.unused
58
+ def forward_non_torchscript(self, net_input: Dict[str, Tensor]):
59
+ encoder_input = {
60
+ k: v for k, v in net_input.items() if k != "prev_output_tokens"
61
+ }
62
+ return self.forward(**encoder_input)
63
+
64
+ def reorder_encoder_out(self, encoder_out, new_order):
65
+ """
66
+ Reorder encoder output according to `new_order`.
67
+
68
+ Args:
69
+ encoder_out: output from the ``forward()`` method
70
+ new_order (LongTensor): desired order
71
+
72
+ Returns:
73
+ `encoder_out` rearranged according to `new_order`
74
+ """
75
+ raise NotImplementedError
76
+
77
+ def max_positions(self):
78
+ """Maximum input length supported by the encoder."""
79
+ return 1e6 # an arbitrary large number
80
+
81
+ def upgrade_state_dict_named(self, state_dict, name):
82
+ """Upgrade old state dicts to work with newer code."""
83
+ return state_dict
84
+
85
+ def set_num_updates(self, num_updates):
86
+ """State from trainer to pass along to model at every update."""
87
+
88
+ def _apply(m):
89
+ if hasattr(m, "set_num_updates") and m != self:
90
+ m.set_num_updates(num_updates)
91
+
92
+ self.apply(_apply)